]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #103019 - Kobzol:ci-multistage-python, r=Mark-Simulacrum
authorbors <bors@rust-lang.org>
Sun, 29 Jan 2023 22:14:18 +0000 (22:14 +0000)
committerbors <bors@rust-lang.org>
Sun, 29 Jan 2023 22:14:18 +0000 (22:14 +0000)
Port pgo.sh to Python

This PR ports the `pgo.sh` multi stage build file from bash to Python, to make it easier to add new functionality and gather statistics. Main changes:

1) `pgo.sh` rewritten from Bash to Python. Jump from ~200 Bash LOC to ~650 Python LOC. Bash is, unsurprisingly, more concise for running scripts and binaries.
2) Better logging. Each separate stage is now clearly separated in logs, and the logs can be quickly grepped to find out which stage has completed or failed, and how long it took.
3) Better statistics. At the end of the run, there is now a table that shows the duration of the individual stages, along with a percentual ratio of the total workflow run:

```
2023-01-15T18:13:49.9896916Z stage-build INFO: Timer results
2023-01-15T18:13:49.9902185Z ---------------------------------------------------------
2023-01-15T18:13:49.9902605Z Build rustc (LLVM PGO):                 1815.67s (21.47%)
2023-01-15T18:13:49.9902949Z Gather profiles (LLVM PGO):              418.73s ( 4.95%)
2023-01-15T18:13:49.9903269Z Build rustc (rustc PGO):                 584.46s ( 6.91%)
2023-01-15T18:13:49.9903835Z Gather profiles (rustc PGO):             806.32s ( 9.53%)
2023-01-15T18:13:49.9904154Z Build rustc (LLVM BOLT):                1662.92s (19.66%)
2023-01-15T18:13:49.9904464Z Gather profiles (LLVM BOLT):             715.18s ( 8.46%)
2023-01-15T18:13:49.9914463Z Final build:                            2454.00s (29.02%)
2023-01-15T18:13:49.9914798Z Total duration:                         8457.27s
2023-01-15T18:13:49.9915305Z ---------------------------------------------------------
```

A sample run can be seen [here](https://github.com/rust-lang/rust/actions/runs/3923980164/jobs/6707932029).

I tried to keep the code compatible with Python 3.6 and don't use dependencies, which required me to reimplement some small pieces of functionality (like formatting bytes). I suppose that it shouldn't be so hard to upgrade to a newer Python or install dependencies in the CI container, but I'd like to avoid it if it won't be needed.

The code is in a single file `stage-build.py`, so it's a bit cluttered. I can also separate it into multiple files, although having it in a single file has some benefits. The code could definitely be nicer, but I'm a bit wary of introducing a lot of abstraction and similar stuff, as long as the code is stuffed into a single file.

Currently, the Python pipeline should faithfully mirror the bash pipeline one by one. After this PR, I'd like to try to optimize it, e.g. by caching the LLVM builds on S3.

r? `@Mark-Simulacrum`

2190 files changed:
.github/ISSUE_TEMPLATE/diagnostics.md [deleted file]
.github/ISSUE_TEMPLATE/diagnostics.yaml [new file with mode: 0644]
.github/ISSUE_TEMPLATE/documentation.md [deleted file]
.github/ISSUE_TEMPLATE/documentation.yaml [new file with mode: 0644]
.github/ISSUE_TEMPLATE/ice.md [deleted file]
.github/ISSUE_TEMPLATE/ice.yaml [new file with mode: 0644]
.github/workflows/ci.yml
.mailmap
Cargo.lock
README.md
RELEASES.md
compiler/rustc_abi/src/lib.rs
compiler/rustc_ast/Cargo.toml
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/util/unicode.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/index.rs
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_ast_passes/src/errors.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/dataflow.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
compiler/rustc_borrowck/src/diagnostics/mod.rs
compiler/rustc_borrowck/src/diagnostics/move_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/invalidation.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/member_constraints.rs
compiler/rustc_borrowck/src/nll.rs
compiler/rustc_borrowck/src/place_ext.rs
compiler/rustc_borrowck/src/places_conflict.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/region_infer/opaque_types.rs
compiler/rustc_borrowck/src/session_diagnostics.rs
compiler/rustc_borrowck/src/type_check/canonical.rs
compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
compiler/rustc_borrowck/src/type_check/free_region_relations.rs
compiler/rustc_borrowck/src/type_check/liveness/trace.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_borrowck/src/universal_regions.rs
compiler/rustc_builtin_macros/src/assert/context.rs
compiler/rustc_builtin_macros/src/deriving/clone.rs
compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
compiler/rustc_builtin_macros/src/deriving/debug.rs
compiler/rustc_builtin_macros/src/deriving/decodable.rs
compiler/rustc_builtin_macros/src/deriving/default.rs
compiler/rustc_builtin_macros/src/deriving/encodable.rs
compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
compiler/rustc_builtin_macros/src/deriving/hash.rs
compiler/rustc_builtin_macros/src/env.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_builtin_macros/src/format_foreign.rs
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/constant.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/abi.rs
compiler/rustc_codegen_llvm/src/asm.rs
compiler/rustc_codegen_llvm/src/attributes.rs
compiler/rustc_codegen_llvm/src/back/archive.rs
compiler/rustc_codegen_llvm/src/back/write.rs
compiler/rustc_codegen_llvm/src/builder.rs
compiler/rustc_codegen_llvm/src/callee.rs
compiler/rustc_codegen_llvm/src/common.rs
compiler/rustc_codegen_llvm/src/consts.rs
compiler/rustc_codegen_llvm/src/context.rs
compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata.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/archive.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/linker.rs
compiler/rustc_codegen_ssa/src/back/symbol_export.rs
compiler/rustc_codegen_ssa/src/back/write.rs
compiler/rustc_codegen_ssa/src/base.rs
compiler/rustc_codegen_ssa/src/codegen_attrs.rs
compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
compiler/rustc_codegen_ssa/src/mir/analyze.rs
compiler/rustc_codegen_ssa/src/mir/block.rs
compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
compiler/rustc_codegen_ssa/src/mir/mod.rs
compiler/rustc_codegen_ssa/src/mir/place.rs
compiler/rustc_codegen_ssa/src/mir/statement.rs
compiler/rustc_const_eval/src/const_eval/error.rs
compiler/rustc_const_eval/src/const_eval/fn_queries.rs
compiler/rustc_const_eval/src/const_eval/machine.rs
compiler/rustc_const_eval/src/const_eval/valtrees.rs
compiler/rustc_const_eval/src/interpret/cast.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/intern.rs
compiler/rustc_const_eval/src/interpret/intrinsics.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/interpret/step.rs
compiler/rustc_const_eval/src/interpret/terminator.rs
compiler/rustc_const_eval/src/interpret/util.rs
compiler/rustc_const_eval/src/interpret/validity.rs
compiler/rustc_const_eval/src/interpret/visitor.rs
compiler/rustc_const_eval/src/lib.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/check_consts/mod.rs
compiler/rustc_const_eval/src/transform/promote_consts.rs
compiler/rustc_const_eval/src/transform/validate.rs
compiler/rustc_const_eval/src/util/call_kind.rs
compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
compiler/rustc_const_eval/src/util/type_name.rs
compiler/rustc_data_structures/src/frozen.rs
compiler/rustc_data_structures/src/fx.rs
compiler/rustc_data_structures/src/graph/dominators/mod.rs
compiler/rustc_data_structures/src/graph/implementation/tests.rs
compiler/rustc_data_structures/src/graph/iterate/mod.rs
compiler/rustc_data_structures/src/graph/scc/tests.rs
compiler/rustc_data_structures/src/lib.rs
compiler/rustc_data_structures/src/obligation_forest/mod.rs
compiler/rustc_data_structures/src/sorted_map.rs
compiler/rustc_data_structures/src/sorted_map/index_map.rs
compiler/rustc_data_structures/src/sorted_map/tests.rs
compiler/rustc_data_structures/src/tiny_list.rs
compiler/rustc_data_structures/src/tiny_list/tests.rs
compiler/rustc_data_structures/src/transitive_relation.rs
compiler/rustc_data_structures/src/unord.rs
compiler/rustc_driver/README.md
compiler/rustc_driver/src/lib.rs
compiler/rustc_driver/src/pretty.rs
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0208.md
compiler/rustc_error_codes/src/error_codes/E0387.md
compiler/rustc_error_codes/src/error_codes/E0587.md
compiler/rustc_error_codes/src/error_codes/E0713.md
compiler/rustc_error_codes/src/error_codes/E0714.md
compiler/rustc_error_codes/src/error_codes/E0789.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0792.md [new file with mode: 0644]
compiler/rustc_error_messages/locales/en-US/ast_passes.ftl
compiler/rustc_error_messages/locales/en-US/borrowck.ftl
compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl
compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl
compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
compiler/rustc_error_messages/locales/en-US/infer.ftl
compiler/rustc_error_messages/locales/en-US/lint.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/locales/en-US/ty_utils.ftl
compiler/rustc_error_messages/src/lib.rs
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/emitter.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_expand/src/base.rs
compiler/rustc_expand/src/config.rs
compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/mbe/macro_check.rs
compiler/rustc_expand/src/mbe/macro_rules.rs
compiler/rustc_expand/src/mbe/quoted.rs
compiler/rustc_expand/src/mbe/transcribe.rs
compiler/rustc_expand/src/parse/tests.rs
compiler/rustc_expand/src/proc_macro_server.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/lib.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_hir/src/stable_hash_impls.rs
compiler/rustc_hir_analysis/src/astconv/errors.rs
compiler/rustc_hir_analysis/src/astconv/generics.rs
compiler/rustc_hir_analysis/src/astconv/mod.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/dropck.rs
compiler/rustc_hir_analysis/src/check/intrinsic.rs
compiler/rustc_hir_analysis/src/check/intrinsicck.rs
compiler/rustc_hir_analysis/src/check/mod.rs
compiler/rustc_hir_analysis/src/check/region.rs
compiler/rustc_hir_analysis/src/check/wfcheck.rs
compiler/rustc_hir_analysis/src/check_unused.rs
compiler/rustc_hir_analysis/src/coherence/builtin.rs
compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
compiler/rustc_hir_analysis/src/coherence/mod.rs
compiler/rustc_hir_analysis/src/coherence/orphan.rs
compiler/rustc_hir_analysis/src/coherence/unsafety.rs
compiler/rustc_hir_analysis/src/collect.rs
compiler/rustc_hir_analysis/src/collect/generics_of.rs
compiler/rustc_hir_analysis/src/collect/item_bounds.rs
compiler/rustc_hir_analysis/src/collect/lifetimes.rs
compiler/rustc_hir_analysis/src/collect/predicates_of.rs
compiler/rustc_hir_analysis/src/collect/type_of.rs
compiler/rustc_hir_analysis/src/constrained_generic_params.rs
compiler/rustc_hir_analysis/src/hir_wf_check.rs
compiler/rustc_hir_analysis/src/impl_wf_check.rs
compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
compiler/rustc_hir_analysis/src/lib.rs
compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
compiler/rustc_hir_analysis/src/outlives/utils.rs
compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
compiler/rustc_hir_analysis/src/variance/constraints.rs
compiler/rustc_hir_analysis/src/variance/mod.rs
compiler/rustc_hir_analysis/src/variance/solve.rs
compiler/rustc_hir_analysis/src/variance/test.rs
compiler/rustc_hir_typeck/src/_match.rs
compiler/rustc_hir_typeck/src/callee.rs
compiler/rustc_hir_typeck/src/cast.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/expr_use_visitor.rs
compiler/rustc_hir_typeck/src/fallback.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/gather_locals.rs
compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs
compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
compiler/rustc_hir_typeck/src/generator_interior/mod.rs
compiler/rustc_hir_typeck/src/inherited.rs
compiler/rustc_hir_typeck/src/intrinsicck.rs
compiler/rustc_hir_typeck/src/lib.rs
compiler/rustc_hir_typeck/src/mem_categorization.rs
compiler/rustc_hir_typeck/src/method/confirm.rs
compiler/rustc_hir_typeck/src/method/mod.rs
compiler/rustc_hir_typeck/src/method/probe.rs
compiler/rustc_hir_typeck/src/method/suggest.rs
compiler/rustc_hir_typeck/src/writeback.rs
compiler/rustc_incremental/src/assert_dep_graph.rs
compiler/rustc_incremental/src/persist/dirty_clean.rs
compiler/rustc_index/src/vec.rs
compiler/rustc_infer/src/errors/mod.rs
compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
compiler/rustc_infer/src/infer/canonical/mod.rs
compiler/rustc_infer/src/infer/canonical/query_response.rs
compiler/rustc_infer/src/infer/canonical/substitute.rs
compiler/rustc_infer/src/infer/combine.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
compiler/rustc_infer/src/infer/error_reporting/note.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/freshen.rs
compiler/rustc_infer/src/infer/glb.rs
compiler/rustc_infer/src/infer/lattice.rs
compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
compiler/rustc_infer/src/infer/lub.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/nll_relate/mod.rs
compiler/rustc_infer/src/infer/opaque_types.rs
compiler/rustc_infer/src/infer/outlives/components.rs
compiler/rustc_infer/src/infer/outlives/env.rs
compiler/rustc_infer/src/infer/outlives/obligations.rs
compiler/rustc_infer/src/infer/outlives/verify.rs
compiler/rustc_infer/src/infer/region_constraints/mod.rs
compiler/rustc_infer/src/infer/resolve.rs
compiler/rustc_infer/src/infer/sub.rs
compiler/rustc_infer/src/infer/type_variable.rs
compiler/rustc_infer/src/traits/engine.rs
compiler/rustc_infer/src/traits/mod.rs
compiler/rustc_infer/src/traits/util.rs
compiler/rustc_interface/src/interface.rs
compiler/rustc_interface/src/lib.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/queries.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_interface/src/util.rs
compiler/rustc_lexer/src/lib.rs
compiler/rustc_lexer/src/unescape.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/early.rs
compiler/rustc_lint/src/for_loops_over_fallibles.rs
compiler/rustc_lint/src/internal.rs
compiler/rustc_lint/src/late.rs
compiler/rustc_lint/src/levels.rs
compiler/rustc_lint/src/lib.rs
compiler/rustc_lint/src/lints.rs
compiler/rustc_lint/src/multiple_supertrait_upcastable.rs [new file with mode: 0644]
compiler/rustc_lint/src/nonstandard_style.rs
compiler/rustc_lint/src/pass_by_value.rs
compiler/rustc_lint/src/passes.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_lint_defs/src/lib.rs
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_macros/src/diagnostics/fluent.rs
compiler/rustc_macros/src/type_visitable.rs
compiler/rustc_metadata/Cargo.toml
compiler/rustc_metadata/src/fs.rs
compiler/rustc_metadata/src/locator.rs
compiler/rustc_metadata/src/native_libs.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_metadata/src/rmeta/table.rs
compiler/rustc_middle/src/arena.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/hir/mod.rs
compiler/rustc_middle/src/infer/canonical.rs
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/macros.rs
compiler/rustc_middle/src/mir/basic_blocks.rs
compiler/rustc_middle/src/mir/graph_cyclic_cache.rs [deleted file]
compiler/rustc_middle/src/mir/interpret/mod.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/predecessors.rs [deleted file]
compiler/rustc_middle/src/mir/query.rs
compiler/rustc_middle/src/mir/spanview.rs
compiler/rustc_middle/src/mir/switch_sources.rs [deleted file]
compiler/rustc_middle/src/mir/syntax.rs
compiler/rustc_middle/src/mir/terminator.rs
compiler/rustc_middle/src/mir/traversal.rs
compiler/rustc_middle/src/mir/type_visitable.rs
compiler/rustc_middle/src/mir/visit.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/thir.rs
compiler/rustc_middle/src/thir/print.rs [new file with mode: 0644]
compiler/rustc_middle/src/traits/chalk.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/traits/query.rs
compiler/rustc_middle/src/ty/adt.rs
compiler/rustc_middle/src/ty/assoc.rs
compiler/rustc_middle/src/ty/codec.rs
compiler/rustc_middle/src/ty/consts.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/diagnostics.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/fast_reject.rs
compiler/rustc_middle/src/ty/flags.rs
compiler/rustc_middle/src/ty/fold.rs
compiler/rustc_middle/src/ty/generics.rs
compiler/rustc_middle/src/ty/instance.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/opaque_types.rs
compiler/rustc_middle/src/ty/parameterized.rs
compiler/rustc_middle/src/ty/print/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/subst.rs
compiler/rustc_middle/src/ty/typeck_results.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_middle/src/ty/visit.rs
compiler/rustc_middle/src/ty/walk.rs
compiler/rustc_middle/src/values.rs
compiler/rustc_mir_build/src/build/custom/mod.rs
compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
compiler/rustc_mir_build/src/build/expr/as_operand.rs
compiler/rustc_mir_build/src/build/expr/stmt.rs
compiler/rustc_mir_build/src/build/matches/mod.rs
compiler/rustc_mir_build/src/build/matches/test.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/build/scope.rs
compiler/rustc_mir_build/src/errors.rs
compiler/rustc_mir_build/src/lib.rs
compiler/rustc_mir_build/src/lints.rs
compiler/rustc_mir_build/src/thir/cx/mod.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_build/src/thir/pattern/deconstruct_pat.rs
compiler/rustc_mir_dataflow/src/impls/liveness.rs
compiler/rustc_mir_dataflow/src/impls/mod.rs
compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
compiler/rustc_mir_dataflow/src/move_paths/builder.rs
compiler/rustc_mir_dataflow/src/value_analysis.rs
compiler/rustc_mir_transform/src/add_retag.rs
compiler/rustc_mir_transform/src/check_unsafety.rs
compiler/rustc_mir_transform/src/const_goto.rs
compiler/rustc_mir_transform/src/copy_prop.rs [new file with mode: 0644]
compiler/rustc_mir_transform/src/coverage/counters.rs
compiler/rustc_mir_transform/src/coverage/graph.rs
compiler/rustc_mir_transform/src/coverage/mod.rs
compiler/rustc_mir_transform/src/coverage/spans.rs
compiler/rustc_mir_transform/src/ctfe_limit.rs [new file with mode: 0644]
compiler/rustc_mir_transform/src/dead_store_elimination.rs
compiler/rustc_mir_transform/src/dest_prop.rs
compiler/rustc_mir_transform/src/function_item_references.rs
compiler/rustc_mir_transform/src/generator.rs
compiler/rustc_mir_transform/src/inline.rs
compiler/rustc_mir_transform/src/instcombine.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
compiler/rustc_mir_transform/src/separate_const_switch.rs
compiler/rustc_mir_transform/src/shim.rs
compiler/rustc_mir_transform/src/simplify.rs
compiler/rustc_mir_transform/src/simplify_try.rs [deleted file]
compiler/rustc_mir_transform/src/sroa.rs
compiler/rustc_mir_transform/src/ssa.rs [new file with mode: 0644]
compiler/rustc_monomorphize/src/collector.rs
compiler/rustc_monomorphize/src/lib.rs
compiler/rustc_monomorphize/src/polymorphize.rs
compiler/rustc_parse/src/errors.rs
compiler/rustc_parse/src/lexer/diagnostics.rs [new file with mode: 0644]
compiler/rustc_parse/src/lexer/mod.rs
compiler/rustc_parse/src/lexer/tokentrees.rs
compiler/rustc_parse/src/lexer/unicode_chars.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/parser/pat.rs
compiler/rustc_parse/src/parser/path.rs
compiler/rustc_parse/src/parser/stmt.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_parse_format/src/lib.rs
compiler/rustc_parse_format/src/tests.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/check_const.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/entry.rs
compiler/rustc_passes/src/errors.rs
compiler/rustc_passes/src/hir_stats.rs
compiler/rustc_passes/src/lang_items.rs
compiler/rustc_passes/src/lib_features.rs
compiler/rustc_passes/src/liveness.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_system/src/dep_graph/graph.rs
compiler/rustc_query_system/src/dep_graph/serialized.rs
compiler/rustc_query_system/src/query/caches.rs
compiler/rustc_resolve/src/check_unused.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/ident.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_save_analysis/src/dump_visitor.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_save_analysis/src/sig.rs
compiler/rustc_save_analysis/src/span_utils.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/cstore.rs
compiler/rustc_session/src/filesearch.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/output.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/source_map/tests.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
compiler/rustc_symbol_mangling/src/v0.rs
compiler/rustc_target/src/abi/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_target/src/asm/mod.rs
compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
compiler/rustc_target/src/spec/bpf_base.rs
compiler/rustc_target/src/spec/i686_apple_darwin.rs
compiler/rustc_target/src/spec/illumos_base.rs
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs
compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
compiler/rustc_trait_selection/Cargo.toml
compiler/rustc_trait_selection/src/lib.rs
compiler/rustc_trait_selection/src/solve/assembly.rs
compiler/rustc_trait_selection/src/solve/cache.rs [deleted file]
compiler/rustc_trait_selection/src/solve/fulfill.rs
compiler/rustc_trait_selection/src/solve/infcx_ext.rs
compiler/rustc_trait_selection/src/solve/mod.rs
compiler/rustc_trait_selection/src/solve/overflow.rs [deleted file]
compiler/rustc_trait_selection/src/solve/project_goals.rs
compiler/rustc_trait_selection/src/solve/search_graph/cache.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/solve/search_graph/mod.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/solve/trait_goals.rs
compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
compiler/rustc_trait_selection/src/traits/coherence.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/engine.rs
compiler/rustc_trait_selection/src/traits/error_reporting/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/fulfill.rs
compiler/rustc_trait_selection/src/traits/misc.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/object_safety.rs
compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
compiler/rustc_trait_selection/src/traits/query/normalize.rs
compiler/rustc_trait_selection/src/traits/relationships.rs [deleted file]
compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_trait_selection/src/traits/specialize/mod.rs
compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
compiler/rustc_trait_selection/src/traits/structural_match.rs
compiler/rustc_trait_selection/src/traits/vtable.rs
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_traits/src/chalk/db.rs
compiler/rustc_traits/src/chalk/lowering.rs
compiler/rustc_traits/src/chalk/mod.rs
compiler/rustc_traits/src/codegen.rs
compiler/rustc_traits/src/dropck_outlives.rs
compiler/rustc_traits/src/implied_outlives_bounds.rs
compiler/rustc_traits/src/type_op.rs
compiler/rustc_transmute/src/lib.rs
compiler/rustc_ty_utils/src/abi.rs
compiler/rustc_ty_utils/src/consts.rs
compiler/rustc_ty_utils/src/implied_bounds.rs
compiler/rustc_ty_utils/src/layout.rs
compiler/rustc_ty_utils/src/lib.rs
compiler/rustc_ty_utils/src/needs_drop.rs
compiler/rustc_ty_utils/src/ty.rs
compiler/rustc_type_ir/src/lib.rs
compiler/rustc_type_ir/src/sty.rs
config.toml.example
library/alloc/src/alloc.rs
library/alloc/src/boxed/thin.rs
library/alloc/src/collections/binary_heap/mod.rs
library/alloc/src/collections/binary_heap/tests.rs
library/alloc/src/lib.rs
library/alloc/src/rc.rs
library/alloc/src/slice.rs
library/alloc/src/str.rs
library/alloc/src/sync.rs
library/alloc/src/sync/tests.rs
library/alloc/src/vec/drain.rs
library/alloc/src/vec/into_iter.rs
library/alloc/src/vec/is_zero.rs
library/alloc/src/vec/mod.rs
library/alloc/src/vec/splice.rs
library/alloc/tests/lib.rs
library/alloc/tests/vec.rs
library/core/src/any.rs
library/core/src/array/iter.rs
library/core/src/cell.rs
library/core/src/cell/once.rs
library/core/src/error.rs
library/core/src/fmt/mod.rs
library/core/src/fmt/rt/v1.rs
library/core/src/future/mod.rs
library/core/src/hint.rs
library/core/src/intrinsics/mir.rs
library/core/src/iter/adapters/filter_map.rs
library/core/src/iter/adapters/flatten.rs
library/core/src/iter/range.rs
library/core/src/iter/sources/from_generator.rs
library/core/src/iter/traits/double_ended.rs
library/core/src/iter/traits/iterator.rs
library/core/src/lib.rs
library/core/src/marker.rs
library/core/src/num/dec2flt/fpu.rs
library/core/src/num/int_macros.rs
library/core/src/ops/control_flow.rs
library/core/src/option.rs
library/core/src/pin.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mod.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/ptr/non_null.rs
library/core/src/slice/iter.rs
library/core/src/slice/iter/macros.rs
library/core/src/slice/mod.rs
library/core/src/slice/sort.rs
library/core/src/sync/atomic.rs
library/core/src/task/wake.rs
library/core/tests/num/dec2flt/mod.rs
library/core/tests/slice.rs
library/portable-simd/crates/core_simd/examples/spectral_norm.rs
library/proc_macro/src/lib.rs
library/std/src/fs.rs
library/std/src/fs/tests.rs
library/std/src/io/buffered/tests.rs
library/std/src/io/error/repr_bitpacked.rs
library/std/src/io/error/tests.rs
library/std/src/lib.rs
library/std/src/net/ip_addr/tests.rs
library/std/src/net/socket_addr.rs
library/std/src/net/socket_addr/tests.rs
library/std/src/os/fd/mod.rs
library/std/src/os/fd/owned.rs
library/std/src/os/net/linux_ext/addr.rs
library/std/src/os/net/mod.rs
library/std/src/os/unix/net/addr.rs
library/std/src/panicking.rs
library/std/src/path.rs
library/std/src/personality/emcc.rs
library/std/src/personality/gcc.rs
library/std/src/sync/mpmc/array.rs
library/std/src/sync/mpmc/utils.rs
library/std/src/sys/common/alloc.rs
library/std/src/sys/hermit/thread.rs
library/std/src/sys/hermit/thread_local_dtor.rs
library/std/src/sys/itron/thread.rs
library/std/src/sys/solid/thread_local_dtor.rs
library/std/src/sys/unix/fs.rs
library/std/src/sys/unix/kernel_copy.rs
library/std/src/sys/unix/process/process_fuchsia.rs
library/std/src/sys/unix/process/process_unix.rs
library/std/src/sys/unix/process/process_unix/tests.rs
library/std/src/sys/unix/process/process_vxworks.rs
library/std/src/sys/unix/thread.rs
library/std/src/sys/unix/thread_local_dtor.rs
library/std/src/sys/windows/os.rs
library/std/src/sys/windows/thread.rs
library/std/src/sys/windows/thread_parking.rs
library/std/src/sys_common/net.rs
library/std/src/sys_common/thread_local_dtor.rs
library/std/src/thread/local.rs
library/std/src/time.rs
library/std/tests/run-time-detect.rs
library/stdarch
library/test/src/cli.rs
library/test/src/console.rs
library/test/src/formatters/terse.rs
library/test/src/lib.rs
library/test/src/term/terminfo/searcher.rs
library/test/src/tests.rs
src/bootstrap/bin/main.rs
src/bootstrap/bootstrap.py
src/bootstrap/cc_detect.rs
src/bootstrap/config.rs
src/bootstrap/config/tests.rs
src/bootstrap/dist.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/tool.rs
src/ci/docker/host-x86_64/arm-android/Dockerfile
src/ci/docker/host-x86_64/dist-android/Dockerfile
src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile
src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
src/ci/docker/host-x86_64/mingw-check/Dockerfile
src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in
src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt
src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh
src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile [new file with mode: 0644]
src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile [new file with mode: 0644]
src/ci/docker/scripts/android-ndk.sh
src/ci/github-actions/ci.yml
src/ci/scripts/install-mingw.sh
src/doc/book
src/doc/nomicon
src/doc/reference
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/doc/rustc/src/instrument-coverage.md
src/doc/unstable-book/src/compiler-flags/tiny-const-eval-limit.md [new file with mode: 0644]
src/etc/pre-push.sh
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/blanket_impl.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/simplify.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/core.rs
src/librustdoc/doctest.rs
src/librustdoc/formats/cache.rs
src/librustdoc/html/format.rs
src/librustdoc/html/length_limit.rs
src/librustdoc/html/length_limit/tests.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/context.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/render/search_index.rs
src/librustdoc/html/render/write_shared.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/settings.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/css/themes/dark.css
src/librustdoc/html/static/css/themes/light.css
src/librustdoc/html/static/js/main.js
src/librustdoc/html/static/js/search.js
src/librustdoc/html/static/js/settings.js
src/librustdoc/html/templates/print_item.html
src/librustdoc/json/import_finder.rs
src/librustdoc/json/mod.rs
src/librustdoc/lib.rs
src/librustdoc/passes/calculate_doc_coverage.rs
src/librustdoc/passes/check_doc_test_visibility.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_intra_doc_links/early.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/passes/lint/check_code_block_syntax.rs
src/librustdoc/passes/propagate_doc_cfg.rs
src/librustdoc/visit_ast.rs
src/librustdoc/visit_lib.rs
src/llvm-project
src/tools/cargo
src/tools/clippy/.github/workflows/clippy_bors.yml
src/tools/clippy/CHANGELOG.md
src/tools/clippy/Cargo.toml
src/tools/clippy/README.md
src/tools/clippy/book/src/SUMMARY.md
src/tools/clippy/book/src/configuration.md
src/tools/clippy/book/src/development/adding_lints.md
src/tools/clippy/book/src/development/infrastructure/book.md
src/tools/clippy/book/src/development/infrastructure/changelog_update.md
src/tools/clippy/book/src/lint_configuration.md [new file with mode: 0644]
src/tools/clippy/clippy_lints/Cargo.toml
src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
src/tools/clippy/clippy_lints/src/booleans.rs
src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
src/tools/clippy/clippy_lints/src/casts/mod.rs
src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
src/tools/clippy/clippy_lints/src/declared_lints.rs
src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/derive.rs
src/tools/clippy/clippy_lints/src/doc.rs
src/tools/clippy/clippy_lints/src/enum_variants.rs
src/tools/clippy/clippy_lints/src/escape.rs
src/tools/clippy/clippy_lints/src/excessive_bools.rs
src/tools/clippy/clippy_lints/src/exhaustive_items.rs
src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
src/tools/clippy/clippy_lints/src/format_args.rs
src/tools/clippy/clippy_lints/src/from_over_into.rs
src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
src/tools/clippy/clippy_lints/src/functions/mod.rs
src/tools/clippy/clippy_lints/src/functions/must_use.rs
src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
src/tools/clippy/clippy_lints/src/functions/result.rs
src/tools/clippy/clippy_lints/src/future_not_send.rs
src/tools/clippy/clippy_lints/src/implicit_return.rs
src/tools/clippy/clippy_lints/src/inherent_impl.rs
src/tools/clippy/clippy_lints/src/inherent_to_string.rs
src/tools/clippy/clippy_lints/src/instant_subtraction.rs
src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/let_underscore.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/lifetimes.rs
src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
src/tools/clippy/clippy_lints/src/manual_async_fn.rs
src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
src/tools/clippy/clippy_lints/src/map_unit_fn.rs
src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
src/tools/clippy/clippy_lints/src/misc.rs
src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
src/tools/clippy/clippy_lints/src/missing_inline.rs
src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/mut_key.rs
src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
src/tools/clippy/clippy_lints/src/new_without_default.rs
src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
src/tools/clippy/clippy_lints/src/ptr.rs
src/tools/clippy/clippy_lints/src/redundant_clone.rs
src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
src/tools/clippy/clippy_lints/src/returns.rs
src/tools/clippy/clippy_lints/src/self_named_constructors.rs
src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
src/tools/clippy/clippy_lints/src/transmute/mod.rs
src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
src/tools/clippy/clippy_lints/src/transmute/utils.rs
src/tools/clippy/clippy_lints/src/types/mod.rs
src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
src/tools/clippy/clippy_lints/src/unused_async.rs
src/tools/clippy/clippy_lints/src/unwrap.rs
src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
src/tools/clippy/clippy_lints/src/use_self.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
src/tools/clippy/clippy_utils/Cargo.toml
src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/macros.rs
src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/clippy/clippy_utils/src/visitors.rs
src/tools/clippy/declare_clippy_lint/Cargo.toml
src/tools/clippy/rust-toolchain
src/tools/clippy/src/main.rs
src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
src/tools/clippy/tests/ui/bool_assert_comparison.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/bool_assert_comparison.rs
src/tools/clippy/tests/ui/bool_assert_comparison.stderr
src/tools/clippy/tests/ui/cast.rs
src/tools/clippy/tests/ui/cast.stderr
src/tools/clippy/tests/ui/cast_size.stderr
src/tools/clippy/tests/ui/module_name_repetitions.stderr
src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/needless_return.fixed
src/tools/clippy/tests/ui/needless_return.rs
src/tools/clippy/tests/ui/needless_return.stderr
src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr
src/tools/clippy/tests/ui/unnecessary_safety_comment.rs
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/read2.rs
src/tools/compiletest/src/runtest.rs
src/tools/compiletest/src/util.rs
src/tools/miri/src/bin/miri.rs
src/tools/miri/src/eval.rs
src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs
src/tools/miri/tests/pass/vec.rs
src/tools/publish_toolstate.py
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/Cargo.toml
src/tools/tidy/src/deps.rs
src/tools/tidy/src/error_codes.rs
src/tools/tidy/src/lib.rs
src/tools/tidy/src/main.rs
src/tools/tidy/src/rustdoc_gui_tests.rs [new file with mode: 0644]
src/tools/tidy/src/style.rs
src/tools/tidy/src/x_version.rs [new file with mode: 0644]
src/version
tests/assembly/is_aligned.rs
tests/codegen/abi-sysv64.rs
tests/codegen/abi-x86-interrupt.rs
tests/codegen/adjustments.rs
tests/codegen/avr/avr-func-addrspace.rs
tests/codegen/box-maybe-uninit-llvm14.rs
tests/codegen/box-maybe-uninit.rs
tests/codegen/c-variadic.rs
tests/codegen/call-llvm-intrinsics.rs
tests/codegen/comparison-operators-newtype.rs
tests/codegen/debug-vtable.rs
tests/codegen/dllimports/main.rs
tests/codegen/enum-match.rs
tests/codegen/fastcall-inreg.rs
tests/codegen/fewer-names.rs
tests/codegen/frame-pointer.rs
tests/codegen/function-arguments.rs
tests/codegen/intrinsics/const_eval_select.rs
tests/codegen/intrinsics/mask.rs
tests/codegen/issue-32031.rs
tests/codegen/issue-45964-bounds-check-slice-pos.rs
tests/codegen/issue-58881.rs
tests/codegen/issue-96497-slice-size-nowrap.rs
tests/codegen/iter-repeat-n-trivial-drop.rs
tests/codegen/loads.rs
tests/codegen/naked-functions.rs
tests/codegen/option-nonzero-eq.rs
tests/codegen/pic-relocation-model.rs
tests/codegen/pie-relocation-model.rs
tests/codegen/refs.rs
tests/codegen/repr-transparent.rs
tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs
tests/codegen/sanitizer-cfi-emit-type-checks.rs
tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs
tests/codegen/sanitizer-recover.rs
tests/codegen/scalar-pair-bool.rs
tests/codegen/some-abis-do-extend-params-to-32-bits.rs
tests/codegen/static-relocation-model-msvc.rs
tests/codegen/transmute-scalar.rs
tests/codegen/tuple-layout-opt.rs
tests/codegen/var-names.rs
tests/codegen/vec-calloc.rs
tests/codegen/zst-offset.rs
tests/debuginfo/embedded-visualizer.rs
tests/debuginfo/numeric-types.rs
tests/debuginfo/vec-slices.rs
tests/mir-opt/76803_regression.encode.SimplifyBranchSame.diff [deleted file]
tests/mir-opt/76803_regression.rs [deleted file]
tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir [new file with mode: 0644]
tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir [new file with mode: 0644]
tests/mir-opt/building/async_await.rs [new file with mode: 0644]
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/consts.rs
tests/mir-opt/building/custom/consts.statics.built.after.mir
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/building/custom/simple_assign.rs
tests/mir-opt/building/custom/simple_assign.simple.built.after.mir
tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff
tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
tests/mir-opt/const_prop/boolean_identities.test.ConstProp.diff
tests/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff
tests/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff
tests/mir-opt/const_prop/mutable_variable_no_prop.rs
tests/mir-opt/const_prop/ref_deref.main.ConstProp.diff
tests/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff [deleted file]
tests/mir-opt/const_prop/ref_deref.rs
tests/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
tests/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff [deleted file]
tests/mir-opt/const_prop/ref_deref_project.rs
tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
tests/mir-opt/const_prop/slice_len.rs
tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff
tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff
tests/mir-opt/const_prop_miscompile.rs
tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/borrowed_local.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/branch.foo.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/branch.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/copy_propagation_arg.baz.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/copy_propagation_arg.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/cycle.main.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/cycle.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.mir [new file with mode: 0644]
tests/mir-opt/copy-prop/dead_stores_79191.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.mir [new file with mode: 0644]
tests/mir-opt/copy-prop/dead_stores_better.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/move_arg.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/mutate_through_pointer.f.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/mutate_through_pointer.rs [new file with mode: 0644]
tests/mir-opt/copy-prop/non_dominate.f.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/non_dominate.rs [new file with mode: 0644]
tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.diff
tests/mir-opt/div_overflow.const_dividend.PreCodegen.after.mir
tests/mir-opt/div_overflow.const_divisor.PreCodegen.after.mir
tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
tests/mir-opt/inline/dyn_trait.get_query.Inline.diff
tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff
tests/mir-opt/inline/inline_any_operand.bar.Inline.after.mir
tests/mir-opt/inline/inline_generator.main.Inline.diff
tests/mir-opt/inline/inline_into_box_place.main.Inline.diff
tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
tests/mir-opt/inline/issue_106141.outer.Inline.diff [new file with mode: 0644]
tests/mir-opt/inline/issue_106141.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_101973.inner.ConstProp.diff
tests/mir-opt/issue_73223.main.SimplifyArmIdentity.diff [deleted file]
tests/mir-opt/issue_73223.rs [deleted file]
tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff
tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
tests/mir-opt/issues/issue_75439.rs
tests/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir
tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir
tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir
tests/mir-opt/simplify_match.main.ConstProp.diff
tests/mir-opt/slice_filter.rs [new file with mode: 0644]
tests/mir-opt/slice_filter.variant_a-{closure#0}.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff [new file with mode: 0644]
tests/mir-opt/slice_filter.variant_b-{closure#0}.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/slice_filter.variant_b-{closure#0}.DestinationPropagation.diff [new file with mode: 0644]
tests/mir-opt/try_identity_e2e.new.PreCodegen.after.mir
tests/mir-opt/try_identity_e2e.old.PreCodegen.after.mir
tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir
tests/pretty/dollar-crate.pp
tests/pretty/issue-4264.pp
tests/run-make-fulldeps/issue-19371/foo.rs
tests/run-make-fulldeps/split-debuginfo/Makefile
tests/run-make/native-link-modifier-bundle/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/run-make/raw-dylib-inline-cross-dylib/Makefile
tests/run-make/rlib-format-packed-bundled-libs-2/Makefile
tests/run-make/rlib-format-packed-bundled-libs/Makefile
tests/rustdoc-gui/basic-code.goml
tests/rustdoc-gui/code-tags.goml
tests/rustdoc-gui/font-weight.goml
tests/rustdoc-gui/label-next-to-symbol.goml
tests/rustdoc-gui/list_code_block.goml
tests/rustdoc-gui/mobile.goml
tests/rustdoc-gui/module-items-font.goml
tests/rustdoc-gui/scrape-examples-button-focus.goml
tests/rustdoc-gui/scrape-examples-color.goml
tests/rustdoc-gui/settings.goml
tests/rustdoc-gui/src-font-size.goml
tests/rustdoc-gui/theme-change.goml
tests/rustdoc-gui/unsafe-fn.goml
tests/rustdoc-js-std/macro-print.js
tests/rustdoc-js-std/typed-query.js
tests/rustdoc-js-std/vec-new.js
tests/rustdoc-js/search-short-types.js
tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs
tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr [deleted file]
tests/rustdoc-ui/infinite-recursive-type-impl-trait.rs
tests/rustdoc-ui/infinite-recursive-type-impl-trait.stderr [deleted file]
tests/rustdoc-ui/invalid-syntax.stderr
tests/rustdoc-ui/z-help.stdout
tests/rustdoc/anchors.no_const_anchor.html
tests/rustdoc/anchors.no_const_anchor2.html
tests/rustdoc/anchors.no_method_anchor.html
tests/rustdoc/anchors.no_trait_method_anchor.html
tests/rustdoc/anchors.no_tymethod_anchor.html
tests/rustdoc/anchors.no_type_anchor.html
tests/rustdoc/anchors.no_type_anchor2.html
tests/rustdoc/array-links.rs
tests/rustdoc/assoc-consts.rs
tests/rustdoc/assoc-item-cast.rs
tests/rustdoc/assoc-types.rs
tests/rustdoc/async-fn.rs
tests/rustdoc/attributes.rs
tests/rustdoc/auxiliary/issue-85454.rs
tests/rustdoc/cfg_doc_reexport.rs
tests/rustdoc/const-fn.rs
tests/rustdoc/const-generics/add-impl.rs
tests/rustdoc/const-generics/const-generic-defaults.rs
tests/rustdoc/const-generics/const-generic-slice.rs
tests/rustdoc/const-generics/const-generics-docs.rs
tests/rustdoc/const-generics/const-impl.rs
tests/rustdoc/const-generics/generic_const_exprs.rs
tests/rustdoc/const-generics/type-alias.rs
tests/rustdoc/const-intrinsic.rs
tests/rustdoc/deprecated.rs
tests/rustdoc/doc-assoc-item.rs
tests/rustdoc/doc-cfg.rs
tests/rustdoc/doc-notable_trait-slice.bare_fn_matches.html
tests/rustdoc/doc-notable_trait.bare-fn.html
tests/rustdoc/doc-notable_trait.some-struct-new.html
tests/rustdoc/doc-notable_trait.wrap-me.html
tests/rustdoc/duplicate-cfg.rs
tests/rustdoc/duplicate_impls/issue-33054.rs
tests/rustdoc/duplicated_impl.rs
tests/rustdoc/empty-impl-block-private-with-doc.rs
tests/rustdoc/empty-impl-block-private.rs
tests/rustdoc/empty-impl-block.rs
tests/rustdoc/fn-pointer-arg-name.rs
tests/rustdoc/glob-shadowing.rs
tests/rustdoc/hide-complex-unevaluated-const-arguments.rs
tests/rustdoc/impl-in-const-block.rs [deleted file]
tests/rustdoc/impl-parts.rs
tests/rustdoc/inline-default-methods.rs
tests/rustdoc/inline_cross/auxiliary/cross-glob.rs
tests/rustdoc/inline_cross/cross-glob.rs
tests/rustdoc/inline_cross/dyn_trait.rs
tests/rustdoc/inline_cross/impl_trait.rs
tests/rustdoc/inline_cross/issue-31948-1.rs
tests/rustdoc/inline_cross/issue-31948-2.rs
tests/rustdoc/inline_cross/issue-31948.rs
tests/rustdoc/inline_cross/macros.rs
tests/rustdoc/issue-107350.rs [new file with mode: 0644]
tests/rustdoc/issue-20646.rs
tests/rustdoc/issue-20727-2.rs
tests/rustdoc/issue-20727-3.rs
tests/rustdoc/issue-20727-4.rs
tests/rustdoc/issue-20727.rs
tests/rustdoc/issue-21474.rs
tests/rustdoc/issue-22038.rs
tests/rustdoc/issue-32374.rs
tests/rustdoc/issue-33302.rs
tests/rustdoc/issue-45584.rs
tests/rustdoc/issue-50159.rs
tests/rustdoc/issue-51236.rs
tests/rustdoc/issue-53812.rs
tests/rustdoc/issue-54705.rs
tests/rustdoc/issue-55321.rs
tests/rustdoc/issue-55364.rs
tests/rustdoc/issue-56822.rs
tests/rustdoc/issue-60726.rs
tests/rustdoc/issue-76501.rs
tests/rustdoc/issue-78673.rs
tests/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs
tests/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs
tests/rustdoc/issue-85454.rs
tests/rustdoc/issue-95873.rs
tests/rustdoc/issue-98697.rs
tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs
tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs
tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs
tests/rustdoc/legacy-const-generic.rs
tests/rustdoc/lifetime-name.rs
tests/rustdoc/mut-params.rs
tests/rustdoc/negative-impl.rs
tests/rustdoc/normalize-assoc-item.rs
tests/rustdoc/playground-arg.rs
tests/rustdoc/playground.rs
tests/rustdoc/primitive-reference.rs
tests/rustdoc/pub-method.rs
tests/rustdoc/range-arg-pattern.rs
tests/rustdoc/reexport-check.rs
tests/rustdoc/reexports-priv.rs
tests/rustdoc/reexports.rs
tests/rustdoc/rfc-2632-const-trait-impl.rs
tests/rustdoc/safe-intrinsic.rs
tests/rustdoc/slice-links.rs
tests/rustdoc/spotlight-from-dependency.odd.html
tests/rustdoc/struct-arg-pattern.rs
tests/rustdoc/synthetic_auto/basic.rs
tests/rustdoc/synthetic_auto/complex.rs
tests/rustdoc/synthetic_auto/lifetimes.rs
tests/rustdoc/synthetic_auto/manual.rs
tests/rustdoc/synthetic_auto/negative.rs
tests/rustdoc/synthetic_auto/nested.rs
tests/rustdoc/synthetic_auto/no-redundancy.rs
tests/rustdoc/synthetic_auto/project.rs
tests/rustdoc/synthetic_auto/self-referential.rs
tests/rustdoc/synthetic_auto/static-region.rs
tests/rustdoc/test-parens.rs
tests/rustdoc/toggle-item-contents.rs
tests/rustdoc/tuple-struct-fields-doc.rs
tests/rustdoc/tuples.rs
tests/rustdoc/typedef.rs
tests/rustdoc/unit-return.rs
tests/rustdoc/where-sized.rs
tests/rustdoc/where.SWhere_Simd_item-decl.html
tests/rustdoc/where.SWhere_TraitWhere_item-decl.html
tests/rustdoc/where.rs
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/rustdoc/whitespace-after-where-clause.trait.html
tests/rustdoc/whitespace-after-where-clause.trait2.html
tests/rustdoc/whitespace-after-where-clause.union.html
tests/rustdoc/whitespace-after-where-clause.union2.html
tests/rustdoc/wrapping.rs
tests/ui-fulldeps/auxiliary/issue-40001-plugin.rs
tests/ui-fulldeps/dropck-tarena-cycle-checked.stderr
tests/ui-fulldeps/dropck-tarena-unsound-drop.stderr
tests/ui-fulldeps/fluent-messages/missing-message-ref.ftl [new file with mode: 0644]
tests/ui-fulldeps/fluent-messages/test.rs
tests/ui-fulldeps/fluent-messages/test.stderr
tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs
tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
tests/ui-fulldeps/mod_dir_path_canonicalized.rs
tests/ui/anonymous-higher-ranked-lifetime.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/associated-types/issue-43784-associated-type.stderr
tests/ui/async-await/async-await-let-else.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/async-await-let-else.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/async-await-let-else.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/async-await-let-else.rs
tests/ui/async-await/async-error-span.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/async-error-span.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/async-error-span.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/async-error-span.rs
tests/ui/async-await/async-error-span.stderr [deleted file]
tests/ui/async-await/async-fn-nonsend.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/async-fn-nonsend.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/async-fn-nonsend.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/async-fn-nonsend.rs
tests/ui/async-await/async-fn-nonsend.stderr
tests/ui/async-await/auxiliary/issue-107036.rs [new file with mode: 0644]
tests/ui/async-await/await-sequence.rs [new file with mode: 0644]
tests/ui/async-await/default-struct-update.rs
tests/ui/async-await/drop-and-assign.rs
tests/ui/async-await/drop-track-field-assign-nonsend.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/drop-track-field-assign-nonsend.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/drop-track-field-assign-nonsend.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/drop-track-field-assign-nonsend.rs
tests/ui/async-await/drop-track-field-assign-nonsend.stderr [deleted file]
tests/ui/async-await/drop-track-field-assign.rs
tests/ui/async-await/field-assign-nonsend.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/field-assign-nonsend.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/field-assign-nonsend.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/field-assign-nonsend.rs [new file with mode: 0644]
tests/ui/async-await/field-assign.rs [new file with mode: 0644]
tests/ui/async-await/in-trait/missing-send-bound.rs [new file with mode: 0644]
tests/ui/async-await/in-trait/missing-send-bound.stderr [new file with mode: 0644]
tests/ui/async-await/issue-107036.rs [new file with mode: 0644]
tests/ui/async-await/issue-64130-1-sync.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-64130-1-sync.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/issue-64130-1-sync.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-64130-1-sync.rs
tests/ui/async-await/issue-64130-1-sync.stderr
tests/ui/async-await/issue-64130-2-send.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-64130-2-send.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/issue-64130-2-send.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-64130-2-send.rs
tests/ui/async-await/issue-64130-2-send.stderr
tests/ui/async-await/issue-64130-3-other.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-64130-3-other.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/issue-64130-3-other.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-64130-3-other.rs
tests/ui/async-await/issue-64130-3-other.stderr
tests/ui/async-await/issue-64130-4-async-move.drop-tracking.stderr
tests/ui/async-await/issue-64130-4-async-move.no_drop_tracking.stderr
tests/ui/async-await/issue-64130-4-async-move.rs
tests/ui/async-await/issue-67252-unnamed-future.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-67252-unnamed-future.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/issue-67252-unnamed-future.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-67252-unnamed-future.rs
tests/ui/async-await/issue-67252-unnamed-future.stderr [deleted file]
tests/ui/async-await/issue-68112.drop_tracking.stderr
tests/ui/async-await/issue-68112.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/issue-68112.no_drop_tracking.stderr
tests/ui/async-await/issue-68112.rs
tests/ui/async-await/issue-70818.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-70818.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/issue-70818.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-70818.rs
tests/ui/async-await/issue-70818.stderr
tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/issue-70935-complex-spans.rs
tests/ui/async-await/issue-73741-type-err-drop-tracking.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-73741-type-err-drop-tracking.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/issue-73741-type-err-drop-tracking.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-73741-type-err-drop-tracking.rs
tests/ui/async-await/issue-73741-type-err-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/issue-86507.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-86507.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/issue-86507.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/issue-86507.rs
tests/ui/async-await/issue-86507.stderr [deleted file]
tests/ui/async-await/issue-93648.rs
tests/ui/async-await/issues/auxiliary/issue_67893.rs
tests/ui/async-await/issues/issue-65436-raw-ptr-not-send.no_drop_tracking.stderr
tests/ui/async-await/issues/issue-65436-raw-ptr-not-send.rs
tests/ui/async-await/issues/issue-67611-static-mut-refs.rs
tests/ui/async-await/issues/issue-67893.stderr
tests/ui/async-await/multiple-lifetimes/ret-ref.stderr
tests/ui/async-await/mutually-recursive-async-impl-trait-type.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/mutually-recursive-async-impl-trait-type.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/mutually-recursive-async-impl-trait-type.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs
tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr
tests/ui/async-await/non-trivial-drop.rs
tests/ui/async-await/recursive-async-impl-trait-type.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/recursive-async-impl-trait-type.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/recursive-async-impl-trait-type.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/recursive-async-impl-trait-type.rs
tests/ui/async-await/recursive-async-impl-trait-type.stderr
tests/ui/async-await/send-bound-async-closure.rs [new file with mode: 0644]
tests/ui/async-await/unresolved_type_param.drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/unresolved_type_param.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/async-await/unresolved_type_param.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/async-await/unresolved_type_param.rs
tests/ui/async-await/unresolved_type_param.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/issue-92157.rs [new file with mode: 0644]
tests/ui/borrowck/issue-92157.stderr [new file with mode: 0644]
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/cast/cast-as-bool.rs
tests/ui/cast/cast-as-bool.stderr
tests/ui/cast/issue-106883-is-empty.rs [new file with mode: 0644]
tests/ui/cast/issue-106883-is-empty.stderr [new file with mode: 0644]
tests/ui/chalkify/bugs/async.rs
tests/ui/chalkify/bugs/async.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/closures/issue-84128.stderr
tests/ui/closures/issue-87461.stderr
tests/ui/closures/multiple-fn-bounds.stderr
tests/ui/coercion/coerce-overloaded-autoderef-fail.stderr
tests/ui/coherence/coherence-with-generator.rs
tests/ui/coherence/coherence-with-generator.stderr [deleted file]
tests/ui/coherence/coherence-with-generator.stock.stderr [new file with mode: 0644]
tests/ui/const-generics/bad-const-generic-exprs.rs
tests/ui/const-generics/bad-const-generic-exprs.stderr
tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
tests/ui/const-generics/const-param-type-depends-on-const-param.rs
tests/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr
tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr
tests/ui/const-generics/generic_const_exprs/auxiliary/anon_const_non_local.rs [new file with mode: 0644]
tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs [new file with mode: 0644]
tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr [new file with mode: 0644]
tests/ui/const-generics/generic_const_exprs/issue-62504.min.stderr
tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.stderr
tests/ui/const-generics/generic_const_exprs/let-bindings.stderr
tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.rs [new file with mode: 0644]
tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr [new file with mode: 0644]
tests/ui/const-generics/generic_const_exprs/unused_expr.stderr
tests/ui/const-generics/issue-106419-struct-with-multiple-const-params.rs [new file with mode: 0644]
tests/ui/const-generics/issues/issue-62878.min.stderr
tests/ui/const-generics/issues/issue-62878.rs
tests/ui/const-generics/issues/issue-67945-2.full.stderr
tests/ui/const-generics/issues/issue-67945-3.full.stderr
tests/ui/const-generics/issues/issue-67945-4.full.stderr
tests/ui/const-generics/issues/issue-71169.min.stderr
tests/ui/const-generics/issues/issue-71169.rs
tests/ui/const-generics/issues/issue-73491.min.stderr
tests/ui/const-generics/issues/issue-73491.rs
tests/ui/const-generics/issues/issue-74101.min.stderr
tests/ui/const-generics/issues/issue-74101.rs
tests/ui/const-generics/issues/issue-75047.min.stderr
tests/ui/const-generics/issues/issue-75047.rs
tests/ui/const-generics/issues/issue-77357.stderr
tests/ui/const-generics/issues/issue-85031-2.rs
tests/ui/const-generics/issues/issue-85031-2.stderr
tests/ui/const-generics/issues/issue-90318.rs
tests/ui/const-generics/issues/issue-90318.stderr
tests/ui/const-generics/min_const_generics/macro-fail.stderr
tests/ui/const-generics/nested-type.min.stderr
tests/ui/const-generics/unused_braces.fixed
tests/ui/const-generics/unused_braces.rs
tests/ui/const-generics/unused_braces.stderr
tests/ui/consts/auxiliary/closure-in-foreign-crate.rs [new file with mode: 0644]
tests/ui/consts/closure-in-foreign-crate.rs [new file with mode: 0644]
tests/ui/consts/const-eval/infinite_loop.stderr
tests/ui/consts/const-eval/issue-52475.rs
tests/ui/consts/const-eval/issue-52475.stderr
tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.rs [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.stderr [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.rs [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.stderr [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-recursion.rs [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-recursion.stderr [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.stderr [new file with mode: 0644]
tests/ui/consts/const-eval/stable-metric/dominators-edge-case.rs [new file with mode: 0644]
tests/ui/consts/const-match-check.eval1.stderr
tests/ui/consts/const-match-check.eval2.stderr
tests/ui/consts/const-match-check.matchck.stderr
tests/ui/consts/const-size_of-cycle.stderr
tests/ui/consts/const_cmp_type_id.rs [new file with mode: 0644]
tests/ui/consts/const_limit/const_eval_limit_reached.stderr
tests/ui/consts/issue-44415.stderr
tests/ui/consts/issue-73976-monomorphic.rs
tests/ui/consts/promote_const_let.stderr
tests/ui/consts/too_generic_eval_ice.rs
tests/ui/consts/too_generic_eval_ice.stderr
tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.stderr
tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.stderr
tests/ui/dep-graph/dep-graph-dump.rs [new file with mode: 0644]
tests/ui/dep-graph/dep-graph-dump.stderr [new file with mode: 0644]
tests/ui/derives/issue-91550.stderr
tests/ui/deriving/deriving-all-codegen.stdout
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/empty/empty-macro-use.stderr
tests/ui/error-codes/E0208.rs [new file with mode: 0644]
tests/ui/error-codes/E0208.stderr [new file with mode: 0644]
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/error-codes/E0606.rs
tests/ui/error-codes/E0606.stderr
tests/ui/error-codes/E0789.rs [new file with mode: 0644]
tests/ui/error-codes/E0789.stderr [new file with mode: 0644]
tests/ui/error-festival.stderr
tests/ui/errors/auxiliary/remapped_dep.rs [new file with mode: 0644]
tests/ui/errors/remap-path-prefix-reverse.local-self.stderr [new file with mode: 0644]
tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr [new file with mode: 0644]
tests/ui/errors/remap-path-prefix-reverse.rs [new file with mode: 0644]
tests/ui/errors/remap-path-prefix.rs [new file with mode: 0644]
tests/ui/errors/remap-path-prefix.stderr [new file with mode: 0644]
tests/ui/extenv/issue-55897.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/feature-gates/feature-gate-multiple_supertrait_upcastable.rs [new file with mode: 0644]
tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr [new file with mode: 0644]
tests/ui/fmt/auxiliary/format-string-proc-macro.rs
tests/ui/fmt/indoc-issue-106408.rs [new file with mode: 0644]
tests/ui/fmt/respanned-literal-issue-106191.rs
tests/ui/fmt/respanned-literal-issue-106191.stderr
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/addassign-yield.rs
tests/ui/generator/auto-trait-regions.drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/auto-trait-regions.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/generator/auto-trait-regions.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/auto-trait-regions.rs
tests/ui/generator/auto-trait-regions.stderr
tests/ui/generator/borrowing.drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/borrowing.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/generator/borrowing.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/borrowing.rs
tests/ui/generator/borrowing.stderr
tests/ui/generator/drop-tracking-parent-expression.drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/drop-tracking-parent-expression.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/generator/drop-tracking-parent-expression.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/drop-tracking-parent-expression.rs
tests/ui/generator/drop-tracking-parent-expression.stderr [deleted file]
tests/ui/generator/drop-tracking-yielding-in-match-guards.rs
tests/ui/generator/dropck.stderr
tests/ui/generator/issue-105084.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/generator/issue-105084.rs [new file with mode: 0644]
tests/ui/generator/issue-57017.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/issue-57017.rs
tests/ui/generator/issue-57478.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/issue-57478.rs
tests/ui/generator/issue-68112.drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/issue-68112.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/generator/issue-68112.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/issue-68112.rs
tests/ui/generator/issue-68112.stderr [deleted file]
tests/ui/generator/issue-93161.rs
tests/ui/generator/not-send-sync.drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/not-send-sync.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/generator/not-send-sync.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/not-send-sync.rs
tests/ui/generator/not-send-sync.stderr [deleted file]
tests/ui/generator/parent-expression.drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/parent-expression.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/generator/parent-expression.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/parent-expression.rs [new file with mode: 0644]
tests/ui/generator/partial-drop.drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/partial-drop.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/partial-drop.rs
tests/ui/generator/partial-drop.stderr [deleted file]
tests/ui/generator/print/generator-print-verbose-1.drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/print/generator-print-verbose-1.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/generator/print/generator-print-verbose-1.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/print/generator-print-verbose-1.rs
tests/ui/generator/print/generator-print-verbose-1.stderr [deleted file]
tests/ui/generator/print/generator-print-verbose-2.drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/print/generator-print-verbose-2.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/generator/print/generator-print-verbose-2.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/print/generator-print-verbose-2.rs
tests/ui/generator/print/generator-print-verbose-2.stderr [deleted file]
tests/ui/generator/retain-resume-ref.drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/retain-resume-ref.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/generator/retain-resume-ref.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/generator/retain-resume-ref.rs
tests/ui/generator/retain-resume-ref.stderr
tests/ui/generator/static-mut-reference-across-yield.rs
tests/ui/generic-associated-types/bugs/hrtb-implied-1.rs
tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr
tests/ui/generic-associated-types/bugs/hrtb-implied-2.rs
tests/ui/generic-associated-types/bugs/issue-100013.rs
tests/ui/generic-associated-types/bugs/issue-100013.stderr
tests/ui/generic-associated-types/bugs/issue-91762.rs
tests/ui/generic-associated-types/collectivity-regression.stderr
tests/ui/generic-associated-types/issue-74684-1.stderr
tests/ui/generic-associated-types/issue-74824.stderr
tests/ui/generic-associated-types/issue-88360.fixed [new file with mode: 0644]
tests/ui/generic-associated-types/issue-88360.rs
tests/ui/generic-associated-types/issue-88360.stderr
tests/ui/generic-associated-types/missing-bounds.stderr
tests/ui/generics/issue-106694.rs [new file with mode: 0644]
tests/ui/generics/issue-106694.stderr [new file with mode: 0644]
tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs [new file with mode: 0644]
tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr [new file with mode: 0644]
tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr
tests/ui/higher-rank-trait-bounds/issue-42114.rs [new file with mode: 0644]
tests/ui/hygiene/globs.stderr
tests/ui/hygiene/no_implicit_prelude-2018.stderr
tests/ui/impl-trait/feature-self-return-type.stderr
tests/ui/impl-trait/issue-55872-2.drop_tracking.stderr [new file with mode: 0644]
tests/ui/impl-trait/issue-55872-2.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/impl-trait/issue-55872-2.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/impl-trait/issue-55872-2.rs
tests/ui/impl-trait/issue-55872-2.stderr
tests/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr
tests/ui/impl-trait/issues/issue-105826.rs [new file with mode: 0644]
tests/ui/impl-trait/recursive-generator.rs [new file with mode: 0644]
tests/ui/impl-trait/recursive-generator.stderr [new file with mode: 0644]
tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking.stderr [new file with mode: 0644]
tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/impl-trait/recursive-impl-trait-type-indirect.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs
tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr [deleted file]
tests/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr
tests/ui/imports/bad-import-in-nested.stderr
tests/ui/imports/bad-import-with-rename.stderr
tests/ui/imports/import-prefix-macro-1.stderr
tests/ui/imports/issue-56125.stderr
tests/ui/imports/issue-57015.stderr
tests/ui/imports/issue-99695-b.fixed [new file with mode: 0644]
tests/ui/imports/issue-99695-b.rs [new file with mode: 0644]
tests/ui/imports/issue-99695-b.stderr [new file with mode: 0644]
tests/ui/imports/issue-99695.fixed [new file with mode: 0644]
tests/ui/imports/issue-99695.rs [new file with mode: 0644]
tests/ui/imports/issue-99695.stderr [new file with mode: 0644]
tests/ui/inference/cannot-infer-partial-try-return.stderr
tests/ui/inference/issue-107090.rs [new file with mode: 0644]
tests/ui/inference/issue-107090.stderr [new file with mode: 0644]
tests/ui/inference/issue-83606.rs
tests/ui/inference/issue-83606.stderr
tests/ui/inference/question-mark-type-infer.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-19100.fixed
tests/ui/issues/issue-19100.rs
tests/ui/issues/issue-19100.stderr
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-65634-raw-ident-suggestion.edition2015.stderr [new file with mode: 0644]
tests/ui/issues/issue-65634-raw-ident-suggestion.edition2018.stderr [new file with mode: 0644]
tests/ui/issues/issue-65634-raw-ident-suggestion.rs
tests/ui/issues/issue-65634-raw-ident-suggestion.stderr [deleted file]
tests/ui/issues/issue-69455.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-105507.fixed [new file with mode: 0644]
tests/ui/lifetimes/issue-105507.rs [new file with mode: 0644]
tests/ui/lifetimes/issue-105507.stderr [new file with mode: 0644]
tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr
tests/ui/limits/issue-15919-32.stderr
tests/ui/limits/issue-15919-64.stderr
tests/ui/limits/issue-17913.rs
tests/ui/limits/issue-17913.stderr
tests/ui/limits/issue-55878.stderr
tests/ui/limits/issue-69485-var-size-diffs-too-large.stderr
tests/ui/limits/issue-75158-64.stderr
tests/ui/lint/issue-30302.rs
tests/ui/lint/issue-30302.stderr
tests/ui/lint/lint-uppercase-variables.rs
tests/ui/lint/lint-uppercase-variables.stderr
tests/ui/lint/must_not_suspend/dedup.drop_tracking.stderr [new file with mode: 0644]
tests/ui/lint/must_not_suspend/dedup.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/lint/must_not_suspend/dedup.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/lint/must_not_suspend/dedup.rs
tests/ui/lint/must_not_suspend/dedup.stderr
tests/ui/lint/must_not_suspend/ref.drop_tracking.stderr
tests/ui/lint/must_not_suspend/ref.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/lint/must_not_suspend/ref.no_drop_tracking.stderr
tests/ui/lint/must_not_suspend/ref.rs
tests/ui/lint/must_not_suspend/trait.drop_tracking.stderr [new file with mode: 0644]
tests/ui/lint/must_not_suspend/trait.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/lint/must_not_suspend/trait.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/lint/must_not_suspend/trait.rs
tests/ui/lint/must_not_suspend/trait.stderr
tests/ui/lint/must_not_suspend/unit.drop_tracking.stderr [new file with mode: 0644]
tests/ui/lint/must_not_suspend/unit.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/lint/must_not_suspend/unit.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/lint/must_not_suspend/unit.rs
tests/ui/lint/must_not_suspend/unit.stderr
tests/ui/lint/must_not_suspend/warn.drop_tracking.stderr [new file with mode: 0644]
tests/ui/lint/must_not_suspend/warn.drop_tracking_mir.stderr [new file with mode: 0644]
tests/ui/lint/must_not_suspend/warn.no_drop_tracking.stderr [new file with mode: 0644]
tests/ui/lint/must_not_suspend/warn.rs
tests/ui/lint/must_not_suspend/warn.stderr
tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr
tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr
tests/ui/lint/unused/issue-105061-array-lint.rs [new file with mode: 0644]
tests/ui/lint/unused/issue-105061-array-lint.stderr [new file with mode: 0644]
tests/ui/lint/unused/issue-105061-should-lint.rs [new file with mode: 0644]
tests/ui/lint/unused/issue-105061-should-lint.stderr [new file with mode: 0644]
tests/ui/lint/unused/issue-105061.rs [new file with mode: 0644]
tests/ui/lint/unused/issue-105061.stderr [new file with mode: 0644]
tests/ui/lint/unused_braces.fixed
tests/ui/lint/unused_braces.rs
tests/ui/lint/unused_braces.stderr
tests/ui/macros/format-args-temporaries-in-write.stderr
tests/ui/macros/issue-84195-lint-anon-const.stderr
tests/ui/macros/issue-88228.rs
tests/ui/macros/issue-88228.stderr
tests/ui/macros/lint-trailing-macro-call.stderr
tests/ui/macros/macro-context.stderr
tests/ui/macros/macro-in-expression-context.stderr
tests/ui/macros/macro-use-wrong-name.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/methods/method-not-found-but-doc-alias.rs [new file with mode: 0644]
tests/ui/methods/method-not-found-but-doc-alias.stderr [new file with mode: 0644]
tests/ui/mir/mir_codegen_ssa.rs [new file with mode: 0644]
tests/ui/mismatched_types/cast-rfc0401.stderr
tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed [new file with mode: 0644]
tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs [new file with mode: 0644]
tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr [new file with mode: 0644]
tests/ui/mismatched_types/closure-arg-type-mismatch.stderr
tests/ui/mismatched_types/issue-35030.stderr
tests/ui/mismatched_types/issue-36053-2.stderr
tests/ui/missing-trait-bounds/issue-35677.stderr
tests/ui/missing/missing-macro-use.stderr
tests/ui/moves/move-fn-self-receiver.stderr
tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed [new file with mode: 0644]
tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs [new file with mode: 0644]
tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr [new file with mode: 0644]
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/deli-ident-issue-1.rs [new file with mode: 0644]
tests/ui/parser/deli-ident-issue-1.stderr [new file with mode: 0644]
tests/ui/parser/deli-ident-issue-2.rs [new file with mode: 0644]
tests/ui/parser/deli-ident-issue-2.stderr [new file with mode: 0644]
tests/ui/parser/fake-anon-enums-in-macros.rs [new file with mode: 0644]
tests/ui/parser/issue-68987-unmatch-issue-1.rs [new file with mode: 0644]
tests/ui/parser/issue-68987-unmatch-issue-1.stderr [new file with mode: 0644]
tests/ui/parser/issue-68987-unmatch-issue-2.rs [new file with mode: 0644]
tests/ui/parser/issue-68987-unmatch-issue-2.stderr [new file with mode: 0644]
tests/ui/parser/issue-68987-unmatch-issue-3.rs [new file with mode: 0644]
tests/ui/parser/issue-68987-unmatch-issue-3.stderr [new file with mode: 0644]
tests/ui/parser/issue-68987-unmatch-issue.rs [new file with mode: 0644]
tests/ui/parser/issue-68987-unmatch-issue.stderr [new file with mode: 0644]
tests/ui/parser/issue-81827.stderr
tests/ui/parser/issues/issue-44406.stderr
tests/ui/parser/issues/issue-62973.stderr
tests/ui/parser/issues/issue-63116.stderr
tests/ui/parser/issues/issue-66473.stderr
tests/ui/parser/issues/issue-68629.stderr
tests/ui/parser/issues/issue-68730.stderr
tests/ui/parser/issues/issue-69259.rs [new file with mode: 0644]
tests/ui/parser/issues/issue-69259.stderr [new file with mode: 0644]
tests/ui/parser/issues/issue-70583-block-is-empty-1.stderr
tests/ui/parser/issues/issue-70583-block-is-empty-2.stderr
tests/ui/parser/issues/issue-87086-colon-path-sep.rs
tests/ui/parser/issues/issue-87086-colon-path-sep.stderr
tests/ui/parser/macro-mismatched-delim-paren-brace.stderr
tests/ui/parser/recover-unticked-labels.fixed [new file with mode: 0644]
tests/ui/parser/recover-unticked-labels.rs [new file with mode: 0644]
tests/ui/parser/recover-unticked-labels.stderr [new file with mode: 0644]
tests/ui/parser/trait-object-delimiters.rs
tests/ui/parser/trait-object-delimiters.stderr
tests/ui/parser/unicode-chars.rs
tests/ui/parser/unicode-chars.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/issue-106552.rs [new file with mode: 0644]
tests/ui/pattern/issue-106552.stderr [new file with mode: 0644]
tests/ui/pattern/issue-14221.rs
tests/ui/pattern/issue-14221.stderr
tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs
tests/ui/pattern/issue-67776-match-same-name-enum-variant-refs.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/derive-helper-shadowing.stderr
tests/ui/proc-macro/expand-expr.rs
tests/ui/proc-macro/expand-expr.stderr
tests/ui/proc-macro/generate-mod.rs
tests/ui/proc-macro/generate-mod.stderr
tests/ui/proc-macro/pretty-print-hack-show.remapped.stderr
tests/ui/proc-macro/pretty-print-hack-show.remapped.stdout
tests/ui/proc-macro/pretty-print-hack-show.rs
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/remap-path-prefix.rs [deleted file]
tests/ui/remap-path-prefix.stderr [deleted file]
tests/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr
tests/ui/rfc-2126-extern-absolute-paths/not-allowed.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/rust-2018/edition-lint-infer-outlives-multispan.rs
tests/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr
tests/ui/rust-2018/edition-lint-infer-outlives.fixed
tests/ui/rust-2018/edition-lint-infer-outlives.rs
tests/ui/rust-2018/edition-lint-infer-outlives.stderr
tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs
tests/ui/self/issue-61882-2.stderr
tests/ui/simd/portable-intrinsics-arent-exposed.stderr
tests/ui/single-use-lifetime/issue-104440.rs [new file with mode: 0644]
tests/ui/single-use-lifetime/issue-104440.stderr [new file with mode: 0644]
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/stability-attribute/issue-106589.rs [new file with mode: 0644]
tests/ui/stability-attribute/issue-106589.stderr [new file with mode: 0644]
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/args-instead-of-tuple-errors.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/call-on-unimplemented-with-autoderef.rs [new file with mode: 0644]
tests/ui/suggestions/call-on-unimplemented-with-autoderef.stderr [new file with mode: 0644]
tests/ui/suggestions/constrain-suggest-ice.stderr
tests/ui/suggestions/issue-88730.rs
tests/ui/suggestions/issue-88730.stderr
tests/ui/suggestions/late-bound-in-borrow-closure-sugg.rs [new file with mode: 0644]
tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr [new file with mode: 0644]
tests/ui/suggestions/option-content-move2.stderr
tests/ui/suggestions/ref-pattern-binding.stderr
tests/ui/suggestions/sugg-else-for-closure.stderr
tests/ui/suggestions/suggest-remove-deref.fixed [new file with mode: 0644]
tests/ui/suggestions/suggest-remove-deref.rs [new file with mode: 0644]
tests/ui/suggestions/suggest-remove-deref.stderr [new file with mode: 0644]
tests/ui/suggestions/type-mismatch-byte-literal.rs [new file with mode: 0644]
tests/ui/suggestions/type-mismatch-byte-literal.stderr [new file with mode: 0644]
tests/ui/symbol-names/basic.legacy.stderr
tests/ui/symbol-names/impl2.rs
tests/ui/symbol-names/impl2.stderr
tests/ui/symbol-names/issue-60925.legacy.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/test-attrs/inaccessible-test-modules.stderr
tests/ui/thir-print/thir-flat.rs [new file with mode: 0644]
tests/ui/thir-print/thir-flat.stdout [new file with mode: 0644]
tests/ui/thir-print/thir-tree-match.rs [new file with mode: 0644]
tests/ui/thir-print/thir-tree-match.stdout [new file with mode: 0644]
tests/ui/thir-print/thir-tree.rs [new file with mode: 0644]
tests/ui/thir-print/thir-tree.stdout [new file with mode: 0644]
tests/ui/thir-tree.rs [deleted file]
tests/ui/thir-tree.stdout [deleted file]
tests/ui/traits/alias/issue-60755.rs [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/copy-impl-cannot-normalize.stderr
tests/ui/traits/copy-is-not-modulo-regions.not_static.stderr [new file with mode: 0644]
tests/ui/traits/copy-is-not-modulo-regions.rs [new file with mode: 0644]
tests/ui/traits/copy-requires-self-wf.rs [new file with mode: 0644]
tests/ui/traits/fn-trait-cast-diagnostic.rs [new file with mode: 0644]
tests/ui/traits/fn-trait-cast-diagnostic.stderr [new file with mode: 0644]
tests/ui/traits/issue-106072.rs [new file with mode: 0644]
tests/ui/traits/issue-106072.stderr [new file with mode: 0644]
tests/ui/traits/issue-43784-supertrait.stderr
tests/ui/traits/issue-50480.rs
tests/ui/traits/issue-50480.stderr
tests/ui/traits/issue-52893.stderr
tests/ui/traits/issue-99875.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/fn-trait-closure.rs [new file with mode: 0644]
tests/ui/traits/new-solver/fn-trait.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/new-solver/pointer-sized.rs [new file with mode: 0644]
tests/ui/traits/new-solver/pointer-sized.stderr [new file with mode: 0644]
tests/ui/traits/track-obligations.rs [new file with mode: 0644]
tests/ui/traits/track-obligations.stderr [new file with mode: 0644]
tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs [new file with mode: 0644]
tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr [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/bound_reduction2.rs
tests/ui/type-alias-impl-trait/bound_reduction2.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-alias-impl-trait/generic_type_does_not_live_long_enough.rs
tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
tests/ui/type-alias-impl-trait/issue-104817.rs [new file with mode: 0644]
tests/ui/type-alias-impl-trait/issue-104817.stock.stderr [new file with mode: 0644]
tests/ui/type-alias-impl-trait/issue-53092-2.rs
tests/ui/type-alias-impl-trait/issue-53092-2.stderr
tests/ui/type-alias-impl-trait/issue-60564.rs
tests/ui/type-alias-impl-trait/issue-60564.stderr
tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs
tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr
tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs
tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr
tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs
tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr
tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs
tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr
tests/ui/type-alias-impl-trait/outlives-bound-var.rs [new file with mode: 0644]
tests/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.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/type/wrong-call-return-type-due-to-generic-arg.rs [new file with mode: 0644]
tests/ui/type/wrong-call-return-type-due-to-generic-arg.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/typeck/issue-104513-ice.stderr
tests/ui/typeck/issue-107087.rs [new file with mode: 0644]
tests/ui/typeck/issue-107087.stderr [new file with mode: 0644]
tests/ui/typeck/issue-46112.stderr
tests/ui/typeck/issue-84768.stderr
tests/ui/typeck/issue-91334.stderr
tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr
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/unresolved/unresolved-candidates.stderr
tests/ui/variance/variance-associated-consts.stderr
tests/ui/variance/variance-associated-types.rs
tests/ui/variance/variance-associated-types.stderr
tests/ui/variance/variance-issue-20533.stderr
tests/ui/variance/variance-object-types.stderr
tests/ui/variance/variance-regions-direct.rs
tests/ui/variance/variance-regions-direct.stderr
tests/ui/variance/variance-regions-indirect.rs
tests/ui/variance/variance-regions-indirect.stderr
tests/ui/variance/variance-trait-bounds.stderr
tests/ui/variance/variance-trait-object-bound.rs
tests/ui/variance/variance-trait-object-bound.stderr
tests/ui/variance/variance-types-bounds.stderr
tests/ui/variance/variance-types.rs
tests/ui/variance/variance-types.stderr
triagebot.toml

diff --git a/.github/ISSUE_TEMPLATE/diagnostics.md b/.github/ISSUE_TEMPLATE/diagnostics.md
deleted file mode 100644 (file)
index a7b70ce..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
----
-name: Diagnostic issue
-about: Create a bug report or feature request for a change to `rustc`'s error output
-labels: A-diagnostics, T-compiler
----
-<!--
-Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
-along with any information you feel relevant to replicating the bug.
-
-If you cannot produce a minimal reproduction case (something that would work in
-isolation), please provide the steps or even link to a repository that causes
-the problematic output to occur.
--->
-
-Given the following code: <!-- Please provide a link to play.rust-lang.org -->
-
-```rust
-<code>
-```
-
-The current output is:
-
-```
-<rustc output>
-```
-
-<!-- The following is not always necessary. -->
-Ideally the output should look like:
-
-```
-<proposed output>
-```
-
-<!--
-If the problem is not self-explanatory, please provide a rationale for the
-change.
--->
-
-<!--
-If dramatically different output is caused by small changes, consider also
-adding them here.
-
-If you're using the stable version of the compiler, you should also check if the
-bug also exists in the beta or nightly versions. The output might also be
-different depending on the Edition.
--->
diff --git a/.github/ISSUE_TEMPLATE/diagnostics.yaml b/.github/ISSUE_TEMPLATE/diagnostics.yaml
new file mode 100644 (file)
index 0000000..873fbaa
--- /dev/null
@@ -0,0 +1,65 @@
+name: Diagnostic issue
+description: Create a bug report or feature request for a change to `rustc`'s error output
+labels: ["A-diagnostics", "T-compiler"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        Thank you for filing a diagnostics bug report! 🐛
+
+        Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug.
+
+        If you cannot produce a minimal reproduction case (something that would work in isolation), please provide the steps or even link to a repository that causes the problematic output to occur.
+  - type: textarea
+    id: code
+    attributes:
+      label: Code
+      description: Please provide code that can reproduce the problem
+      placeholder: code
+      render: Rust
+    validations:
+      required: true
+  - type: textarea
+    id: output
+    attributes:
+      label: Current output
+      description: Please provide the `rustc` output you see
+      placeholder: rustc output
+      render: Shell
+    validations:
+      required: true
+  - type: textarea
+    id: desired-output
+    attributes:
+      label: Desired output
+      description: Please provide what the output *should* be
+      placeholder: proposed output
+      render: Shell
+    validations:
+      required: false
+  - type: textarea
+    id: rationale
+    attributes:
+      label: Rationale and extra context
+      description: If the problem is not self-explanatory, please provide a rationale for the change.
+    validations:
+      required: false
+  - type: textarea
+    id: other-output
+    attributes:
+      label: Other cases
+      description: If dramatically different output is caused by small changes, consider also adding them here.
+      render: Rust
+    validations:
+      required: false
+  - type: markdown
+    attributes:
+      value: |
+        If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. The output might also be different depending on the Edition.
+  - type: textarea
+    id: extra
+    attributes:
+      label: Anything else?
+      description: If you have more details you want to give us to reproduce this issue, please add it here
+    validations:
+      required: false
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md
deleted file mode 100644 (file)
index 9ccda17..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
----
-name: Documentation problem
-about: Create a report for a documentation problem.
-labels: A-docs
----
-<!--
-
-Thank you for finding a documentation problem! 📚
-
-Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present.
-
-Note: If your issue is for one of these, please use their dedicated issue tracker instead:
-
-- The Rust Book: https://github.com/rust-lang/book/issues
-- Rust by Example: https://github.com/rust-lang/rust-by-example/issues
-- The Edition Guide: https://github.com/rust-lang/edition-guide/issues
-- The Cargo Book: https://github.com/rust-lang/cargo/issues
-- The Clippy Book: https://github.com/rust-lang/rust-clippy/issues
-- The Reference: https://github.com/rust-lang/reference/issues
-- The Rustonomicon: https://github.com/rust-lang/nomicon/issues
-- The Embedded Book: https://github.com/rust-embedded/book/issues
-
-All other documentation issues should be filed here.
-
-Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
-
--->
-
-### Location
-
-### Summary
diff --git a/.github/ISSUE_TEMPLATE/documentation.yaml b/.github/ISSUE_TEMPLATE/documentation.yaml
new file mode 100644 (file)
index 0000000..712b327
--- /dev/null
@@ -0,0 +1,38 @@
+name: Documentation problem
+description: Create a report for a documentation problem.
+labels: ["A-docs"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        Thank you for finding a documentation problem! 📚
+
+        Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present.
+
+        Note: If your issue is for one of these, please use their dedicated issue tracker instead:
+        - [The Rust Book](https://github.com/rust-lang/book/issues)
+        - [Rust by Example](https://github.com/rust-lang/rust-by-example/issues)
+        - [The Edition Guide](https://github.com/rust-lang/edition-guide/issues)
+        - [The Cargo Book](https://github.com/rust-lang/cargo/issues)
+        - [The Clippy Book](https://github.com/rust-lang/rust-clippy/issues)
+        - [The Reference](https://github.com/rust-lang/reference/issues)
+        - [The Rustonomicon](https://github.com/rust-lang/nomicon/issues)
+        - [The Embedded Book](https://github.com/rust-embedded/book/issues)
+
+        All other documentation issues should be filed here.
+
+        Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
+
+  - type: textarea
+    id: location
+    attributes:
+      label: Location
+    validations:
+      required: true 
+
+  - type: textarea
+    id: summary
+    attributes:
+      label: Summary
+    validations:
+      required: true 
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/ice.md b/.github/ISSUE_TEMPLATE/ice.md
deleted file mode 100644 (file)
index 03bc4ba..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
----
-name: Internal Compiler Error
-about: Create a report for an internal compiler error in rustc.
-labels: C-bug, I-ICE, T-compiler
----
-<!--
-Thank you for finding an Internal Compiler Error! 🧊  If possible, try to provide
-a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for
-how to create smaller examples.
-
-http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
-
--->
-
-### Code
-
-```Rust
-<code>
-```
-
-
-### Meta
-<!--
-If you're using the stable version of the compiler, you should also check if the
-bug also exists in the beta or nightly versions.
--->
-
-`rustc --version --verbose`:
-```
-<version>
-```
-
-### Error output
-
-```
-<output>
-```
-
-<!--
-Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
-environment. E.g. `RUST_BACKTRACE=1 cargo build`.
--->
-<details><summary><strong>Backtrace</strong></summary>
-<p>
-
-```
-<backtrace>
-```
-
-</p>
-</details>
-
diff --git a/.github/ISSUE_TEMPLATE/ice.yaml b/.github/ISSUE_TEMPLATE/ice.yaml
new file mode 100644 (file)
index 0000000..54136cc
--- /dev/null
@@ -0,0 +1,82 @@
+name: Internal Compiler Error
+description: Create a report for an internal compiler error in `rustc`
+labels: ["C-bug", "I-ICE", "T-compiler"]
+title: "[ICE]: "
+body:
+  - type: markdown
+    attributes:
+      value: |
+        Thank you for finding an Internal Compiler Error! 🧊
+
+        If possible, try to provide a minimal verifiable example.
+
+        You can read "[Rust Bug Minimization Patterns](http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/)" for how to create smaller examples.
+
+  - type: textarea
+    id: code
+    attributes:
+      label: Code
+      description: Please provide code or a link to a repository that can reproduce the problem
+      placeholder: code
+      render: Rust
+    validations:
+      required: false
+
+  - type: checkboxes
+    attributes:
+      label: Affected release channels
+      description: If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions
+      options:
+        - label: Previous Stable
+          required: false
+        - label: Current Stable
+          required: false
+        - label: Current Beta
+          required: false
+        - label: Current Nightly
+          required: false
+
+  - type: textarea
+    id: version
+    attributes:
+      label: Rust Version
+      description: Please provide the `rustc` version, `rustc --version --verbose`
+      placeholder: |
+        $ rustc --version --verbose
+        rustc 1.XX.Y (SHORTHASH DATE)
+        binary: rustc
+        commit-hash: LONGHASHVALUE
+        commit-date: DATE
+        host: PLATFORMTRIPLE
+        release: 1.XX.Y
+        LLVM version: XX.YY.ZZ
+      render: Shell
+    validations:
+      required: true
+
+  - type: textarea
+    id: output
+    attributes:
+      label: Current error output
+      description: Please provide the `rustc` output you see
+      placeholder: output
+      render: Shell
+    validations:
+      required: false
+
+  - type: textarea
+    id: backtrace
+    attributes:
+      label: Backtrace
+      description: Include a backtrace in the code block by setting `RUST_BACKTRACE=full` in your environment, e.g. `RUST_BACKTRACE=full cargo build`
+      render: Shell
+    validations:
+      required: true
+
+  - type: textarea
+    id: extra
+    attributes:
+      label: Anything else?
+      description: If you have more details you want to give us to reproduce this issue, please add it here
+    validations:
+      required: false
\ No newline at end of file
index 04a50f1f107850666b8fea406c778840ac82c471..552680f06f66dd58390c69f5b1c09f3c4205acc8 100644 (file)
@@ -291,6 +291,14 @@ jobs:
           - name: x86_64-gnu-distcheck
             os: ubuntu-20.04-xl
             env: {}
+          - name: x86_64-gnu-llvm-15
+            env:
+              RUST_BACKTRACE: 1
+            os: ubuntu-20.04-xl
+          - name: x86_64-gnu-llvm-14
+            env:
+              RUST_BACKTRACE: 1
+            os: ubuntu-20.04-xl
           - name: x86_64-gnu-llvm-13
             env:
               RUST_BACKTRACE: 1
@@ -410,14 +418,14 @@ jobs:
             os: windows-latest-xl
           - name: i686-mingw-1
             env:
-              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
+              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
               SCRIPT: make ci-mingw-subset-1
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
             os: windows-latest-xl
           - name: i686-mingw-2
             env:
-              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
+              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
               SCRIPT: make ci-mingw-subset-2
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
@@ -425,14 +433,14 @@ jobs:
           - name: x86_64-mingw-1
             env:
               SCRIPT: make ci-mingw-subset-1
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
             os: windows-latest-xl
           - name: x86_64-mingw-2
             env:
               SCRIPT: make ci-mingw-subset-2
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
             os: windows-latest-xl
@@ -457,7 +465,7 @@ jobs:
             os: windows-latest-xl
           - name: dist-i686-mingw
             env:
-              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
+              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler"
               NO_DOWNLOAD_CI_LLVM: 1
               SCRIPT: python x.py dist bootstrap --include-default-paths
               CUSTOM_MINGW: 1
@@ -466,7 +474,7 @@ jobs:
           - name: dist-x86_64-mingw
             env:
               SCRIPT: python x.py dist bootstrap --include-default-paths
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler"
               NO_DOWNLOAD_CI_LLVM: 1
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
index 022cdd0fd50c161b9c3f0c2756fa5a9cd608818f..8ed692989ccbf73baf3dbe06012380237c5b3a56 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -15,6 +15,7 @@ Adrien Tétar <adri-from-59@hotmail.fr>
 Ahmed Charles <ahmedcharles@gmail.com> <acharles@outlook.com>
 Alan Egerton <eggyal@gmail.com>
 Alan Stoate <alan.stoate@gmail.com>
+Albert Larsan <albert.larsan@gmail.com> Albert Larsan <74931857+albertlarsan68@users.noreply.github.com>
 Alessandro Decina <alessandro.d@gmail.com>
 Alex Burka <durka42+github@gmail.com> Alex Burka <aburka@seas.upenn.edu>
 Alex Hansen <ahansen2@trinity.edu>
@@ -324,6 +325,7 @@ Lennart Kudling <github@kudling.de>
 Léo Lanteri Thauvin <leseulartichaut@gmail.com>
 Léo Lanteri Thauvin <leseulartichaut@gmail.com> <38361244+LeSeulArtichaut@users.noreply.github.com>
 Léo Testard <leo.testard@gmail.com>
+León Orell Valerian Liehr <me@fmease.dev> <liehr.exchange@gmx.net>
 Leonardo Yvens <leoyvens@gmail.com>
 Liigo Zhuang <liigo@qq.com>
 Lily Ballard <lily@ballards.net> <kevin@sb.org>
index ee91b00377182fce4c8dedbf1e516d338fe29b6f..b35892ccd523e9cba17f412e8b7817e58f24deb5 100644 (file)
@@ -351,7 +351,7 @@ dependencies = [
  "cargo-test-macro",
  "cargo-test-support",
  "cargo-util",
- "clap 4.0.32",
+ "clap 4.1.4",
  "crates-io",
  "curl",
  "curl-sys",
@@ -551,9 +551,9 @@ version = "0.1.0"
 
 [[package]]
 name = "cc"
-version = "1.0.76"
+version = "1.0.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f"
+checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
 dependencies = [
  "jobserver",
 ]
@@ -655,12 +655,12 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.0.32"
+version = "4.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
+checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
 dependencies = [
  "bitflags",
- "clap_derive 4.0.21",
+ "clap_derive 4.1.0",
  "clap_lex 0.3.0",
  "is-terminal",
  "once_cell",
@@ -675,7 +675,7 @@ version = "4.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
 dependencies = [
- "clap 4.0.32",
+ "clap 4.1.4",
 ]
 
 [[package]]
@@ -693,9 +693,9 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.0.21"
+version = "4.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
+checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
 dependencies = [
  "heck",
  "proc-macro-error",
@@ -724,7 +724,7 @@ dependencies = [
 
 [[package]]
 name = "clippy"
-version = "0.1.68"
+version = "0.1.69"
 dependencies = [
  "clippy_lints",
  "clippy_utils",
@@ -766,7 +766,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.68"
+version = "0.1.69"
 dependencies = [
  "cargo_metadata 0.14.0",
  "clippy_utils",
@@ -789,7 +789,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.68"
+version = "0.1.69"
 dependencies = [
  "arrayvec",
  "if_chain",
@@ -1168,7 +1168,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
 
 [[package]]
 name = "declare_clippy_lint"
-version = "0.1.68"
+version = "0.1.69"
 dependencies = [
  "itertools",
  "quote",
@@ -2294,7 +2294,7 @@ name = "jsondoclint"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "clap 4.0.32",
+ "clap 4.1.4",
  "fs-err",
  "rustdoc-json-types",
  "serde",
@@ -2557,7 +2557,7 @@ dependencies = [
  "ammonia",
  "anyhow",
  "chrono",
- "clap 4.0.32",
+ "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.0.32",
+ "clap 4.1.4",
  "env_logger 0.7.1",
  "mdbook",
 ]
@@ -3672,6 +3672,7 @@ name = "rustc_ast"
 version = "0.0.0"
 dependencies = [
  "bitflags",
+ "memchr",
  "rustc_data_structures",
  "rustc_index",
  "rustc_lexer",
@@ -3729,6 +3730,7 @@ name = "rustc_ast_pretty"
 version = "0.0.0"
 dependencies = [
  "rustc_ast",
+ "rustc_parse_format",
  "rustc_span",
 ]
 
@@ -4326,6 +4328,7 @@ dependencies = [
 name = "rustc_metadata"
 version = "0.0.0"
 dependencies = [
+ "bitflags",
  "libloading",
  "odht",
  "rustc_ast",
@@ -4783,6 +4786,7 @@ dependencies = [
  "rustc_middle",
  "rustc_parse_format",
  "rustc_query_system",
+ "rustc_serialize",
  "rustc_session",
  "rustc_span",
  "rustc_target",
@@ -4924,7 +4928,7 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-config_proc_macro"
-version = "0.2.0"
+version = "0.3.0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4934,7 +4938,7 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-nightly"
-version = "1.5.1"
+version = "1.5.2"
 dependencies = [
  "annotate-snippets",
  "anyhow",
@@ -5212,9 +5216,9 @@ checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2"
 
 [[package]]
 name = "snap"
-version = "1.0.1"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e"
+checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831"
 
 [[package]]
 name = "snapbox"
@@ -5601,11 +5605,13 @@ dependencies = [
 name = "tidy"
 version = "0.1.0"
 dependencies = [
+ "cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "cargo_metadata 0.14.0",
  "ignore",
  "lazy_static",
  "miropt-test-tools",
  "regex",
+ "semver",
  "termcolor",
  "walkdir",
 ]
index ac39435a8c7fb9338a0f278452e2d8ff8afa525d..0eb7c4b266a9f3a529e1b3c555ac2bf1dee974c1 100644 (file)
--- a/README.md
+++ b/README.md
@@ -3,10 +3,11 @@
 This is the main source code repository for [Rust]. It contains the compiler,
 standard library, and documentation.
 
-[Rust]: https://www.rust-lang.org
+[Rust]: https://www.rust-lang.org/
 
 **Note: this README is for _users_ rather than _contributors_.**
-If you wish to _contribute_ to the compiler, you should read [CONTRIBUTING.md](CONTRIBUTING.md) instead.
+If you wish to _contribute_ to the compiler, you should read
+[CONTRIBUTING.md](CONTRIBUTING.md) instead.
 
 ## Quick Start
 
@@ -20,13 +21,15 @@ Read ["Installation"] from [The Book].
 The Rust build system uses a Python script called `x.py` to build the compiler,
 which manages the bootstrapping process. It lives at the root of the project.
 
-The `x.py` command can be run directly on most Unix systems in the following format:
+The `x.py` command can be run directly on most Unix systems in the following
+format:
 
 ```sh
 ./x.py <subcommand> [flags]
 ```
 
-This is how the documentation and examples assume you are running `x.py`. Some alternative ways are:
+This is how the documentation and examples assume you are running `x.py`.
+Some alternative ways are:
 
 ```sh
 # On a Unix shell if you don't have the necessary `python3` command
@@ -39,8 +42,8 @@ x.py <subcommand> [flags]
 python x.py <subcommand> [flags]
 ```
 
-More information about `x.py` can be found
-by running it with the `--help` flag or reading the [rustc dev guide][rustcguidebuild].
+More information about `x.py` can be found by running it with the `--help` flag
+or reading the [rustc dev guide][rustcguidebuild].
 
 [gettingstarted]: https://rustc-dev-guide.rust-lang.org/getting-started.html
 [rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html
@@ -49,24 +52,29 @@ by running it with the `--help` flag or reading the [rustc dev guide][rustcguide
 
 Make sure you have installed the dependencies:
 
-   * `python` 3 or 2.7
-   * `git`
-   * A C compiler (when building for the host, `cc` is enough; cross-compiling may need additional compilers)
-   * `curl` (not needed on Windows)
-   * `pkg-config` if you are compiling on Linux and targeting Linux
-   * `libiconv` (already included with glibc on Debian-based distros)
+* `python` 3 or 2.7
+* `git`
+* A C compiler (when building for the host, `cc` is enough; cross-compiling may
+  need additional compilers)
+* `curl` (not needed on Windows)
+* `pkg-config` if you are compiling on Linux and targeting Linux
+* `libiconv` (already included with glibc on Debian-based distros)
 
-To build cargo, you'll also need OpenSSL (`libssl-dev` or `openssl-devel` on most Unix distros).
+To build Cargo, you'll also need OpenSSL (`libssl-dev` or `openssl-devel` on
+most Unix distros).
 
 If building LLVM from source, you'll need additional tools:
 
 * `g++`, `clang++`, or MSVC with versions listed on
   [LLVM's documentation](https://llvm.org/docs/GettingStarted.html#host-c-toolchain-both-compiler-and-standard-library)
-* `ninja`, or GNU `make` 3.81 or later (ninja is recommended, especially on Windows)
+* `ninja`, or GNU `make` 3.81 or later (Ninja is recommended, especially on
+  Windows)
 * `cmake` 3.13.4 or later
-* `libstdc++-static` may be required on some Linux distributions such as Fedora and Ubuntu
+* `libstdc++-static` may be required on some Linux distributions such as Fedora
+  and Ubuntu
 
-On tier 1 or tier 2 with host tools platforms, you can also choose to download LLVM by setting `llvm.download-ci-llvm = true`.
+On tier 1 or tier 2 with host tools platforms, you can also choose to download
+LLVM by setting `llvm.download-ci-llvm = true`.
 Otherwise, you'll need LLVM installed and `llvm-config` in your path.
 See [the rustc-dev-guide for more info][sysllvm].
 
@@ -86,34 +94,37 @@ See [the rustc-dev-guide for more info][sysllvm].
 
 2. Configure the build settings:
 
-    The Rust build system uses a file named `config.toml` in the root of the
-    source tree to determine various configuration settings for the build.
-    Set up the defaults intended for distros to get started. You can see a full list of options
-    in `config.toml.example`.
+   The Rust build system uses a file named `config.toml` in the root of the
+   source tree to determine various configuration settings for the build.
+   Set up the defaults intended for distros to get started. You can see a full
+   list of options in `config.toml.example`.
 
-    ```sh
-    printf 'profile = "user" \nchangelog-seen = 2 \n' > config.toml
-    ```
+   ```sh
+   printf 'profile = "user" \nchangelog-seen = 2 \n' > config.toml
+   ```
 
-    If you plan to use `x.py install` to create an installation, it is recommended
-    that you set the `prefix` value in the `[install]` section to a directory.
+   If you plan to use `x.py install` to create an installation, it is
+   recommended that you set the `prefix` value in the `[install]` section to a
+   directory.
 
 3. Build and install:
 
-    ```sh
-    ./x.py build && ./x.py install
-    ```
+   ```sh
+   ./x.py build && ./x.py install
+   ```
 
-    When complete, `./x.py install` will place several programs into
-    `$PREFIX/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
-    API-documentation tool. If you've set `profile = "user"` or `build.extended = true`, it will
-    also include [Cargo], Rust's package manager.
+   When complete, `./x.py install` will place several programs into
+   `$PREFIX/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
+   API-documentation tool. If you've set `profile = "user"` or
+   `build.extended = true`, it will also include [Cargo], Rust's package
+   manager.
 
 [Cargo]: https://github.com/rust-lang/cargo
 
 ### Building on Windows
 
-On Windows, we suggest using [winget] to install dependencies by running the following in a terminal:
+On Windows, we suggest using [winget] to install dependencies by running the
+following in a terminal:
 
 ```powershell
 winget install -e Python.Python.3
@@ -121,17 +132,19 @@ winget install -e Kitware.CMake
 winget install -e Git.Git
 ```
 
-Then edit your system's `PATH` variable and add: `C:\Program Files\CMake\bin`. See
-[this guide on editing the system `PATH`](https://www.java.com/en/download/help/path.html) from the
-Java documentation.
+Then edit your system's `PATH` variable and add: `C:\Program Files\CMake\bin`.
+See
+[this guide on editing the system `PATH`](https://www.java.com/en/download/help/path.html)
+from the Java documentation.
 
 [winget]: https://github.com/microsoft/winget-cli
 
 There are two prominent ABIs in use on Windows: the native (MSVC) ABI used by
 Visual Studio and the GNU ABI used by the GCC toolchain. Which version of Rust
 you need depends largely on what C/C++ libraries you want to interoperate with.
-Use the MSVC build of Rust to interop with software produced by Visual Studio and
-the GNU build to interop with GNU software built using the MinGW/MSYS2 toolchain.
+Use the MSVC build of Rust to interop with software produced by Visual Studio
+and the GNU build to interop with GNU software built using the MinGW/MSYS2
+toolchain.
 
 #### MinGW
 
@@ -144,7 +157,7 @@ the GNU build to interop with GNU software built using the MinGW/MSYS2 toolchain
 2. Run `mingw32_shell.bat` or `mingw64_shell.bat` from the MSYS2 installation
    directory (e.g. `C:\msys64`), depending on whether you want 32-bit or 64-bit
    Rust. (As of the latest version of MSYS2 you have to run `msys2_shell.cmd
-   -mingw32` or `msys2_shell.cmd -mingw64` from the command line instead)
+   -mingw32` or `msys2_shell.cmd -mingw64` from the command line instead.)
 
 3. From this terminal, install the required tools:
 
@@ -153,11 +166,11 @@ the GNU build to interop with GNU software built using the MinGW/MSYS2 toolchain
    pacman -Sy pacman-mirrors
 
    # Install build tools needed for Rust. If you're building a 32-bit compiler,
-   # then replace "x86_64" below with "i686". If you've already got git, python,
-   # or CMake installed and in PATH you can remove them from this list. Note
-   # that it is important that you do **not** use the 'python2', 'cmake' and 'ninja'
-   # packages from the 'msys2' subsystem. The build has historically been known
-   # to fail with these packages.
+   # then replace "x86_64" below with "i686". If you've already got Git, Python,
+   # or CMake installed and in PATH you can remove them from this list.
+   # Note that it is important that you do **not** use the 'python2', 'cmake',
+   # and 'ninja' packages from the 'msys2' subsystem.
+   # The build has historically been known to fail with these packages.
    pacman -S git \
                make \
                diffutils \
@@ -178,12 +191,12 @@ the GNU build to interop with GNU software built using the MinGW/MSYS2 toolchain
 
 MSVC builds of Rust additionally require an installation of Visual Studio 2017
 (or later) so `rustc` can use its linker.  The simplest way is to get
-[Visual Studio], check the “C++ build tools” and “Windows 10 SDK” workload.
+[Visual Studio], check the "C++ build tools" and "Windows 10 SDK" workload.
 
 [Visual Studio]: https://visualstudio.microsoft.com/downloads/
 
-(If you're installing cmake yourself, be careful that “C++ CMake tools for
-Windows” doesn't get included under “Individual components”.)
+(If you're installing CMake yourself, be careful that "C++ CMake tools for
+Windows" doesn't get included under "Individual components".)
 
 With these dependencies installed, you can build the compiler in a `cmd.exe`
 shell with:
@@ -192,10 +205,11 @@ shell with:
 python x.py build
 ```
 
-Right now, building Rust only works with some known versions of Visual Studio. If
-you have a more recent version installed and the build system doesn't understand,
-you may need to force rustbuild to use an older version. This can be done
-by manually calling the appropriate vcvars file before running the bootstrap.
+Right now, building Rust only works with some known versions of Visual Studio.
+If you have a more recent version installed and the build system doesn't
+understand, you may need to force rustbuild to use an older version.
+This can be done by manually calling the appropriate vcvars file before running
+the bootstrap.
 
 ```batch
 CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
@@ -215,9 +229,9 @@ Windows build triples are:
     - `x86_64-pc-windows-msvc`
 
 The build triple can be specified by either specifying `--build=<triple>` when
-invoking `x.py` commands, or by creating a `config.toml` file (as described
-in [Installing From Source](#installing-from-source)), and modifying the
-`build` option under the `[build]` section.
+invoking `x.py` commands, or by creating a `config.toml` file (as described in
+[Installing from Source](#installing-from-source)), and modifying the `build`
+option under the `[build]` section.
 
 ### Configure and Make
 
@@ -229,33 +243,35 @@ configure script and makefile (the latter of which just invokes `x.py`).
 make && sudo make install
 ```
 
-`configure` generates a `config.toml` which can also be used with normal `x.py` invocations.
+`configure` generates a `config.toml` which can also be used with normal `x.py`
+invocations.
 
 ## Building Documentation
 
-If you’d like to build the documentation, it’s almost the same:
+If you'd like to build the documentation, it's almost the same:
 
 ```sh
 ./x.py doc
 ```
 
 The generated documentation will appear under `doc` in the `build` directory for
-the ABI used. I.e., if the ABI was `x86_64-pc-windows-msvc`, the directory will be
-`build\x86_64-pc-windows-msvc\doc`.
+the ABI used. That is, if the ABI was `x86_64-pc-windows-msvc`, the directory
+will be `build\x86_64-pc-windows-msvc\doc`.
 
 ## Notes
 
-Since the Rust compiler is written in Rust, it must be built by a
-precompiled "snapshot" version of itself (made in an earlier stage of
-development). As such, source builds require an Internet connection to
-fetch snapshots, and an OS that can execute the available snapshot binaries.
+Since the Rust compiler is written in Rust, it must be built by a precompiled
+"snapshot" version of itself (made in an earlier stage of development).
+As such, source builds require an Internet connection to fetch snapshots, and an
+OS that can execute the available snapshot binaries.
 
-See https://doc.rust-lang.org/nightly/rustc/platform-support.html for a list of supported platforms.
-Only "host tools" platforms have a pre-compiled snapshot binary available; to compile for a platform
-without host tools you must cross-compile.
+See https://doc.rust-lang.org/nightly/rustc/platform-support.html for a list of
+supported platforms.
+Only "host tools" platforms have a pre-compiled snapshot binary available; to
+compile for a platform without host tools you must cross-compile.
 
-You may find that other platforms work, but these are our officially
-supported build environments that are most likely to work.
+You may find that other platforms work, but these are our officially supported
+build environments that are most likely to work.
 
 ## Getting Help
 
@@ -267,9 +283,9 @@ See [CONTRIBUTING.md](CONTRIBUTING.md).
 
 ## License
 
-Rust is primarily distributed under the terms of both the MIT license
-and the Apache License (Version 2.0), with portions covered by various
-BSD-like licenses.
+Rust is primarily distributed under the terms of both the MIT license and the
+Apache License (Version 2.0), with portions covered by various BSD-like
+licenses.
 
 See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and
 [COPYRIGHT](COPYRIGHT) for details.
@@ -277,13 +293,14 @@ See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and
 ## Trademark
 
 [The Rust Foundation][rust-foundation] owns and protects the Rust and Cargo
-trademarks and logos (the “Rust Trademarks”).
+trademarks and logos (the "Rust Trademarks").
 
-If you want to use these names or brands, please read the [media guide][media-guide].
+If you want to use these names or brands, please read the
+[media guide][media-guide].
 
 Third-party logos may be subject to third-party copyrights and trademarks. See
 [Licenses][policies-licenses] for details.
 
 [rust-foundation]: https://foundation.rust-lang.org/
-[media-guide]: https://www.rust-lang.org/policies/media-guide
+[media-guide]: https://foundation.rust-lang.org/policies/logo-policy-and-media-guide/
 [policies-licenses]: https://www.rust-lang.org/policies/licenses
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 4582d3c6badf99491254930d6e7c0f3ee6d7cff8..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
@@ -1100,7 +1092,7 @@ pub enum FieldsShape {
         /// named `inverse_memory_index`.
         ///
         // FIXME(eddyb) build a better abstraction for permutations, if possible.
-        // FIXME(camlorn) also consider small vector  optimization here.
+        // FIXME(camlorn) also consider small vector optimization here.
         memory_index: Vec<u32>,
     },
 }
@@ -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 {
@@ -1263,8 +1256,8 @@ pub enum Variants<V: Idx> {
 
     /// Enum-likes with more than one inhabited variant: each variant comes with
     /// a *discriminant* (usually the same as the variant index but the user can
-    /// assign explicit discriminant values).  That discriminant is encoded
-    /// as a *tag* on the machine.  The layout of each variant is
+    /// assign explicit discriminant values). That discriminant is encoded
+    /// as a *tag* on the machine. The layout of each variant is
     /// a struct, and they all have space reserved for the tag.
     /// For enums, the tag is the sole field of the layout.
     Multiple {
@@ -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 9253b7e6891a25db4592b74ce72c513da14482bb..10d7fa1db605a7dc7c5e70b53fe175c1f60ff185 100644 (file)
@@ -7,6 +7,7 @@ edition = "2021"
 
 [dependencies]
 bitflags = "1.2.1"
+memchr = "2.5.0"
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_index = { path = "../rustc_index" }
 rustc_lexer = { path = "../rustc_lexer" }
index 7de594719ddc44568872ea3ee2516da728a96ada..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,
 }
@@ -2032,7 +2037,8 @@ fn clone(&self) -> Self {
 impl Ty {
     pub fn peel_refs(&self) -> &Self {
         let mut final_ty = self;
-        while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
+        while let TyKind::Ref(_, MutTy { ty, .. }) | TyKind::Ptr(MutTy { ty, .. }) = &final_ty.kind
+        {
             final_ty = ty;
         }
         final_ty
diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs
new file mode 100644 (file)
index 0000000..d021bea
--- /dev/null
@@ -0,0 +1,272 @@
+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 `+` or `-` flag.
+    pub sign: Option<FormatSign>,
+    /// The `#` flag.
+    pub alternate: bool,
+    /// The `0` flag. E.g. the `0` in `{:02x}`.
+    pub zero_pad: bool,
+    /// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`.
+    pub debug_hex: Option<FormatDebugHex>,
+}
+
+#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub enum FormatSign {
+    /// The `+` flag.
+    Plus,
+    /// The `-` flag.
+    Minus,
+}
+
+#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub enum FormatDebugHex {
+    /// The `x` flag in `{:x?}`.
+    Lower,
+    /// The `X` flag in `{:X?}`.
+    Upper,
+}
+
+#[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..23c32fa96ca449e40f705596d897a9a6c0d14f87 100644 (file)
@@ -16,7 +16,6 @@
 #![feature(let_chains)]
 #![feature(min_specialization)]
 #![feature(negative_impls)]
-#![feature(slice_internals)]
 #![feature(stmt_expr_attributes)]
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
@@ -42,6 +41,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 +51,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 819f1884a06922ca5861679de032dde2b2db47a7..81efdaa44b365a3979187d37a540640636784a4f 100644 (file)
@@ -271,6 +271,7 @@ pub enum ExprPrecedence {
     Try,
     InlineAsm,
     Mac,
+    FormatArgs,
 
     Array,
     Repeat,
@@ -304,7 +305,7 @@ pub fn order(self) -> i8 {
             | ExprPrecedence::Yeet => PREC_JUMP,
 
             // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
-            // parse, instead of parsing as `(x .. x) = x`.  Giving `Range` a lower precedence
+            // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
             // ensures that `pprust` will add parentheses in the right places to get the desired
             // parse.
             ExprPrecedence::Range => PREC_RANGE,
@@ -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 0eae791b25e1c66e8da0b93bdfefa0ce7c5585bb..6f57d66b2273a2cf4421d42f8057c4290dfc653e 100644 (file)
@@ -17,7 +17,7 @@ pub fn contains_text_flow_control_chars(s: &str) -> bool {
     // U+2069 - E2 81 A9
     let mut bytes = s.as_bytes();
     loop {
-        match core::slice::memchr::memchr(0xE2, bytes) {
+        match memchr::memchr(0xE2, bytes) {
             Some(idx) => {
                 // bytes are valid UTF-8 -> E2 must be followed by two bytes
                 let ch = &bytes[idx..idx + 3];
index 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..e7dd0b1
--- /dev/null
@@ -0,0 +1,398 @@
+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 &FormatOptions {
+        ref width,
+        ref precision,
+        alignment,
+        fill,
+        sign,
+        alternate,
+        zero_pad,
+        debug_hex,
+    } = &placeholder.format_options;
+    let fill = ctx.expr_char(sp, fill.unwrap_or(' '));
+    let align = ctx.expr_lang_item_type_relative(
+        sp,
+        hir::LangItem::FormatAlignment,
+        match alignment {
+            Some(FormatAlignment::Left) => sym::Left,
+            Some(FormatAlignment::Right) => sym::Right,
+            Some(FormatAlignment::Center) => sym::Center,
+            None => sym::Unknown,
+        },
+    );
+    // This needs to match `FlagV1` in library/core/src/fmt/mod.rs.
+    let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
+        | ((sign == Some(FormatSign::Minus)) as u32) << 1
+        | (alternate as u32) << 2
+        | (zero_pad as u32) << 3
+        | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4
+        | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5;
+    let flags = ctx.expr_u32(sp, flags);
+    let precision = make_count(ctx, sp, &precision, argmap);
+    let width = make_count(ctx, sp, &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, precision, 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 fe0bd43815d7f4393d71c2ec91c033f19557964b..f7fe0d771a13c495cf7f14e77ee9363beba686df 100644 (file)
@@ -38,7 +38,7 @@ pub(super) fn index_hir<'hir>(
 ) -> (IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, FxHashMap<LocalDefId, ItemLocalId>) {
     let mut nodes = IndexVec::new();
     // This node's parent should never be accessed: the owner's parent is computed by the
-    // hir_owner_parent query.  Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is
+    // hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is
     // used.
     nodes.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() }));
     let mut collector = NodeCollector {
@@ -275,19 +275,6 @@ fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) {
         });
     }
 
-    fn visit_fn(
-        &mut self,
-        fk: intravisit::FnKind<'hir>,
-        fd: &'hir FnDecl<'hir>,
-        b: BodyId,
-        _: Span,
-        id: HirId,
-    ) {
-        assert_eq!(self.owner, id.owner);
-        assert_eq!(self.parent_node, id.local_id);
-        intravisit::walk_fn(self, fk, fd, b, id);
-    }
-
     fn visit_block(&mut self, block: &'hir Block<'hir>) {
         self.insert(block.span, block.hir_id, Node::Block(block));
         self.with_parent(block.hir_id, |this| {
index 065779d0670c687b86454b1e90fea8a30f237f2c..2865082bd7a47c5322019389fa660118b1a99cc9 100644 (file)
@@ -67,7 +67,6 @@ fn with_lctx(
             current_hir_id_owner: hir::CRATE_OWNER_ID,
             item_local_id_counter: hir::ItemLocalId::new(0),
             node_id_to_local_id: Default::default(),
-            local_id_to_def_id: SortedMap::new(),
             trait_map: Default::default(),
 
             // Lowering state.
@@ -523,7 +522,7 @@ fn lower_use_tree(
                 //
                 // The first two are produced by recursively invoking
                 // `lower_use_tree` (and indeed there may be things
-                // like `use foo::{a::{b, c}}` and so forth).  They
+                // like `use foo::{a::{b, c}}` and so forth). They
                 // wind up being directly added to
                 // `self.items`. However, the structure of this
                 // function also requires us to return one item, and
index 41d4a5679f1a0b2822396af1256c20e5497350a0..a04a259529310959009d81dec2ca644f71548d31 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;
@@ -118,7 +119,6 @@ struct LoweringContext<'a, 'hir> {
 
     current_hir_id_owner: hir::OwnerId,
     item_local_id_counter: hir::ItemLocalId,
-    local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
     trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>,
 
     impl_trait_defs: Vec<hir::GenericParam<'hir>>,
@@ -416,6 +416,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);
@@ -565,7 +566,6 @@ fn with_hir_id_owner(
         let current_attrs = std::mem::take(&mut self.attrs);
         let current_bodies = std::mem::take(&mut self.bodies);
         let current_node_ids = std::mem::take(&mut self.node_id_to_local_id);
-        let current_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id);
         let current_trait_map = std::mem::take(&mut self.trait_map);
         let current_owner =
             std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id });
@@ -592,7 +592,6 @@ fn with_hir_id_owner(
         self.attrs = current_attrs;
         self.bodies = current_bodies;
         self.node_id_to_local_id = current_node_ids;
-        self.local_id_to_def_id = current_id_to_def_id;
         self.trait_map = current_trait_map;
         self.current_hir_id_owner = current_owner;
         self.item_local_id_counter = current_local_counter;
@@ -627,7 +626,6 @@ fn with_remapping<R>(
     fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
         let attrs = std::mem::take(&mut self.attrs);
         let mut bodies = std::mem::take(&mut self.bodies);
-        let local_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id);
         let trait_map = std::mem::take(&mut self.trait_map);
 
         #[cfg(debug_assertions)]
@@ -643,13 +641,7 @@ fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInf
         let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies);
         let (nodes, parenting) =
             index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies);
-        let nodes = hir::OwnerNodes {
-            hash_including_bodies,
-            hash_without_bodies,
-            nodes,
-            bodies,
-            local_id_to_def_id,
-        };
+        let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies };
         let attrs = {
             let hash = self.tcx.with_stable_hashing_context(|mut hcx| {
                 let mut stable_hasher = StableHasher::new();
@@ -662,7 +654,7 @@ fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInf
         self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
     }
 
-    /// Hash the HIR node twice, one deep and one shallow hash.  This allows to differentiate
+    /// Hash the HIR node twice, one deep and one shallow hash. This allows to differentiate
     /// queries which depend on the full HIR tree and those which only depend on the item signature.
     fn hash_owner(
         &mut self,
@@ -708,7 +700,6 @@ fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
                 assert_ne!(local_id, hir::ItemLocalId::new(0));
                 if let Some(def_id) = self.opt_local_def_id(ast_node_id) {
                     self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
-                    self.local_id_to_def_id.insert(local_id, def_id);
                 }
 
                 if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) {
@@ -1193,7 +1184,7 @@ fn lower_path_ty(
         itctx: &ImplTraitContext,
     ) -> hir::Ty<'hir> {
         // Check whether we should interpret this as a bare trait object.
-        // This check mirrors the one in late resolution.  We only introduce this special case in
+        // This check mirrors the one in late resolution. We only introduce this special case in
         // the rare occurrence we need to lower `Fresh` anonymous lifetimes.
         // The other cases when a qpath should be opportunistically made a trait object are handled
         // by `ty_path`.
@@ -1918,7 +1909,7 @@ fn lower_async_fn_ret_ty(
             this.with_remapping(new_remapping, |this| {
                 // We have to be careful to get elision right here. The
                 // idea is that we create a lifetime parameter for each
-                // lifetime in the return type.  So, given a return type
+                // lifetime in the return type. So, given a return type
                 // like `async fn foo(..) -> &[&u32]`, we lower to `impl
                 // Future<Output = &'1 [ &'2 u32 ]>`.
                 //
@@ -2012,7 +2003,7 @@ fn lower_async_fn_ret_ty(
 
         // Create the `Foo<...>` reference itself. Note that the `type
         // Foo = impl Trait` is, internally, created as a child of the
-        // async fn, so the *type parameters* are inherited.  It's
+        // async fn, so the *type parameters* are inherited. It's
         // only the lifetime parameters that we must supply.
         let opaque_ty_ref = hir::TyKind::OpaqueDef(
             hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
index 55ea12d25ea2ceead70b4c4e6c4de49548a84852..902b4b1a1ecfefb5fa53fbbfd499f2a2b0329dfb 100644 (file)
@@ -1100,16 +1100,17 @@ fn visit_item(&mut self, item: &'a Item) {
                         replace_span: self.ending_semi_or_hi(item.span),
                         extern_block_suggestion: match sig.header.ext {
                             Extern::None => None,
-                            Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
+                            Extern::Implicit(start_span) => Some(ExternBlockSuggestion::Implicit {
                                 start_span,
                                 end_span: item.span.shrink_to_hi(),
-                                abi: None,
-                            }),
-                            Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
-                                start_span,
-                                end_span: item.span.shrink_to_hi(),
-                                abi: Some(abi.symbol_unescaped),
                             }),
+                            Extern::Explicit(abi, start_span) => {
+                                Some(ExternBlockSuggestion::Explicit {
+                                    start_span,
+                                    end_span: item.span.shrink_to_hi(),
+                                    abi: abi.symbol_unescaped,
+                                })
+                            }
                         },
                     });
                 }
index 59f582f10d989be097f5f44eb6ad86827dfd8100..09e262452b11d5819d0f743fa53b0ca1f264f2cd 100644 (file)
@@ -1,6 +1,5 @@
 //! Errors emitted by ast_passes.
 
-use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic, SubdiagnosticMessage};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
@@ -207,28 +206,21 @@ pub struct FnWithoutBody {
     pub extern_block_suggestion: Option<ExternBlockSuggestion>,
 }
 
-pub struct ExternBlockSuggestion {
-    pub start_span: Span,
-    pub end_span: Span,
-    pub abi: Option<Symbol>,
-}
-
-impl AddToDiagnostic for ExternBlockSuggestion {
-    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
-    where
-        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
-    {
-        let start_suggestion = if let Some(abi) = self.abi {
-            format!("extern \"{}\" {{", abi)
-        } else {
-            "extern {".to_owned()
-        };
-        let end_suggestion = " }".to_owned();
-
-        diag.multipart_suggestion(
-            fluent::extern_block_suggestion,
-            vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)],
-            Applicability::MaybeIncorrect,
-        );
-    }
+#[derive(Subdiagnostic)]
+pub enum ExternBlockSuggestion {
+    #[multipart_suggestion(ast_passes_extern_block_suggestion, applicability = "maybe-incorrect")]
+    Implicit {
+        #[suggestion_part(code = "extern {{")]
+        start_span: Span,
+        #[suggestion_part(code = " }}")]
+        end_span: Span,
+    },
+    #[multipart_suggestion(ast_passes_extern_block_suggestion, applicability = "maybe-incorrect")]
+    Explicit {
+        #[suggestion_part(code = "extern \"{abi}\" {{")]
+        start_span: Span,
+        #[suggestion_part(code = " }}")]
+        end_span: Span,
+        abi: Symbol,
+    },
 }
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 b125c6407d05040bb2ed2868332fc90415b1a5bf..cacfe9eb2f10745f8add02cecd528b90ab3a5b0c 100644 (file)
@@ -6,6 +6,11 @@
 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, FormatDebugHex, FormatSign,
+    FormatTrait,
+};
+use std::fmt::Write;
 
 impl<'a> State<'a> {
     fn print_else(&mut self, els: Option<&ast::Expr>) {
@@ -473,10 +478,10 @@ pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline
                 self.word("]");
             }
             ast::ExprKind::Range(start, end, limits) => {
-                // Special case for `Range`.  `AssocOp` claims that `Range` has higher precedence
+                // Special case for `Range`. `AssocOp` claims that `Range` has higher precedence
                 // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
                 // Here we use a fake precedence value so that any child with lower precedence than
-                // a "normal" binop gets parenthesized.  (`LOr` is the lowest-precedence binop.)
+                // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
                 let fake_prec = AssocOp::LOr.precedence() as i8;
                 if let Some(e) = start {
                     self.print_expr_maybe_paren(e, fake_prec);
@@ -527,9 +532,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 +648,88 @@ 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 => {}
+                }
+                match p.format_options.sign {
+                    Some(FormatSign::Plus) => template.push('+'),
+                    Some(FormatSign::Minus) => template.push('-'),
+                    None => {}
+                }
+                if p.format_options.alternate {
+                    template.push('#');
+                }
+                if p.format_options.zero_pad {
+                    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();
+                        }
+                    }
+                }
+                match p.format_options.debug_hex {
+                    Some(FormatDebugHex::Lower) => template.push('x'),
+                    Some(FormatDebugHex::Upper) => template.push('X'),
+                    None => {}
+                }
+                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 8c4885770ad37b6d009eb450d82a7e2b47a4d057..2821677c5371f7857044cd535e24bd14bfd7ca59 100644 (file)
@@ -393,6 +393,7 @@ fn statement_effect(
             | mir::StatementKind::AscribeUserType(..)
             | mir::StatementKind::Coverage(..)
             | mir::StatementKind::Intrinsic(..)
+            | mir::StatementKind::ConstEvalCounter
             | mir::StatementKind::Nop => {}
         }
     }
index 968c1f49b95c00ccec072fc253421936dc258f90..50c0faf4597f1a2cdb36f0a085b0e09e2533cc8a 100644 (file)
@@ -673,40 +673,34 @@ fn suggest_borrow_fn_like(
         let tcx = self.infcx.tcx;
 
         // Find out if the predicates show that the type is a Fn or FnMut
-        let find_fn_kind_from_did = |predicates: ty::EarlyBinder<
-            &[(ty::Predicate<'tcx>, Span)],
-        >,
-                                     substs| {
-            predicates.0.iter().find_map(|(pred, _)| {
-                    let pred = if let Some(substs) = substs {
-                        predicates.rebind(*pred).subst(tcx, substs).kind().skip_binder()
-                    } else {
-                        pred.kind().skip_binder()
-                    };
-                    if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred && pred.self_ty() == ty {
-                    if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
-                        return Some(hir::Mutability::Not);
-                    } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
-                        return Some(hir::Mutability::Mut);
-                    }
+        let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| {
+            if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder()
+                && pred.self_ty() == ty
+            {
+                if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
+                    return Some(hir::Mutability::Not);
+                } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
+                    return Some(hir::Mutability::Mut);
                 }
-                    None
-                })
+            }
+            None
         };
 
         // If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
         // borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
         // These types seem reasonably opaque enough that they could be substituted with their
         // borrowed variants in a function body when we see a move error.
-        let borrow_level = match ty.kind() {
-            ty::Param(_) => find_fn_kind_from_did(
-                tcx.bound_explicit_predicates_of(self.mir_def_id().to_def_id())
-                    .map_bound(|p| p.predicates),
-                None,
-            ),
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
-                find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*def_id), Some(*substs))
-            }
+        let borrow_level = match *ty.kind() {
+            ty::Param(_) => tcx
+                .explicit_predicates_of(self.mir_def_id().to_def_id())
+                .predicates
+                .iter()
+                .copied()
+                .find_map(find_fn_kind_from_did),
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
+                .bound_explicit_item_bounds(def_id)
+                .subst_iter_copied(tcx, substs)
+                .find_map(find_fn_kind_from_did),
             ty::Closure(_, substs) => match substs.as_closure().kind() {
                 ty::ClosureKind::Fn => Some(hir::Mutability::Not),
                 ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
@@ -772,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(
@@ -1742,7 +1736,7 @@ fn report_local_value_does_not_live_long_enough(
                 &self.local_names,
                 &mut err,
                 "",
-                None,
+                Some(borrow_span),
                 None,
             );
         }
@@ -2199,7 +2193,7 @@ fn predecessor_locations<'tcx, 'a>(
         let mut back_edge_stack = Vec::new();
 
         predecessor_locations(self.body, location).for_each(|predecessor| {
-            if location.dominates(predecessor, &self.dominators) {
+            if location.dominates(predecessor, self.dominators()) {
                 back_edge_stack.push(predecessor)
             } else {
                 stack.push(predecessor);
@@ -2311,7 +2305,7 @@ fn predecessor_locations<'tcx, 'a>(
 
             let mut has_predecessor = false;
             predecessor_locations(self.body, location).for_each(|predecessor| {
-                if location.dominates(predecessor, &self.dominators) {
+                if location.dominates(predecessor, self.dominators()) {
                     back_edge_stack.push(predecessor)
                 } else {
                     stack.push(predecessor);
@@ -2605,7 +2599,7 @@ fn annotate_argument_and_return_for_borrow(
                 match ty.kind() {
                     ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
                         self.mir_def_id(),
-                        self.infcx.tcx.fn_sig(self.mir_def_id()),
+                        self.infcx.tcx.fn_sig(self.mir_def_id()).subst_identity(),
                     ),
                     _ => 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 1b40b7143cbb6b671ba2faec06326c362a669de8..8c579bac7e8eb471c8dc8690eb7f7c3a7c62c5d1 100644 (file)
@@ -1064,7 +1064,7 @@ fn explain_captures(
                         );
                     }
                 }
-                CallKind::Normal { self_arg, desugaring, method_did } => {
+                CallKind::Normal { self_arg, desugaring, method_did, method_substs } => {
                     let self_arg = self_arg.unwrap();
                     let tcx = self.infcx.tcx;
                     if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
@@ -1128,15 +1128,19 @@ fn explain_captures(
                                 "{place_name} {partially_str}moved due to this method call{loop_message}",
                             ),
                         );
+
                         let infcx = tcx.infer_ctxt().build();
+                        // Erase and shadow everything that could be passed to the new infcx.
                         let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
+                        let method_substs = tcx.erase_regions(method_substs);
+
                         if let ty::Adt(def, substs) = ty.kind()
                             && Some(def.did()) == tcx.lang_items().pin_type()
                             && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
                             && let self_ty = infcx.replace_bound_vars_with_fresh_vars(
                                 fn_call_span,
                                 LateBoundRegionConversionTime::FnCall,
-                                tcx.fn_sig(method_did).input(0),
+                                tcx.fn_sig(method_did).subst(tcx, method_substs).input(0),
                             )
                             && infcx.can_eq(self.param_env, ty, self_ty).is_ok()
                         {
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 f3050a6ef3f07f7964cf58a23bc3a858dd05b717..87db08ef5b5108e3b6439883ce5d8bb869f90967 100644 (file)
@@ -5,8 +5,13 @@
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
+use rustc_hir::def::Res::Def;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
+use rustc_hir::GenericBound::Trait;
+use rustc_hir::QPath::Resolved;
+use rustc_hir::WherePredicate::BoundPredicate;
+use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
 use rustc_infer::infer::{
     error_reporting::nice_region_error::{
         self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
@@ -186,6 +191,101 @@ fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
         false
     }
 
+    // For generic associated types (GATs) which implied 'static requirement
+    // from higher-ranked trait bounds (HRTB). Try to locate span of the trait
+    // and the span which bounded to the trait for adding 'static lifetime suggestion
+    fn suggest_static_lifetime_for_gat_from_hrtb(
+        &self,
+        diag: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        lower_bound: RegionVid,
+    ) {
+        let mut suggestions = vec![];
+        let hir = self.infcx.tcx.hir();
+
+        // find generic associated types in the given region 'lower_bound'
+        let gat_id_and_generics = self
+            .regioncx
+            .placeholders_contained_in(lower_bound)
+            .map(|placeholder| {
+                if let Some(id) = placeholder.name.get_id()
+                    && let Some(placeholder_id) = id.as_local()
+                    && let gat_hir_id = hir.local_def_id_to_hir_id(placeholder_id)
+                    && let Some(generics_impl) = hir.get_parent(gat_hir_id).generics()
+                {
+                    Some((gat_hir_id, generics_impl))
+                } else {
+                    None
+                }
+            })
+            .collect::<Vec<_>>();
+        debug!(?gat_id_and_generics);
+
+        // find higher-ranked trait bounds bounded to the generic associated types
+        let mut hrtb_bounds = vec![];
+        gat_id_and_generics.iter().flatten().for_each(|(gat_hir_id, generics)| {
+            for pred in generics.predicates {
+                let BoundPredicate(
+                        WhereBoundPredicate {
+                            bound_generic_params,
+                            bounds,
+                            ..
+                        }) = pred else { continue; };
+                if bound_generic_params
+                    .iter()
+                    .rfind(|bgp| hir.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id)
+                    .is_some()
+                {
+                    for bound in *bounds {
+                        hrtb_bounds.push(bound);
+                    }
+                }
+            }
+        });
+        debug!(?hrtb_bounds);
+
+        hrtb_bounds.iter().for_each(|bound| {
+            let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; };
+            diag.span_note(
+                *trait_span,
+                format!("due to current limitations in the borrow checker, this implies a `'static` lifetime")
+            );
+            let Some(generics_fn) = hir.get_generics(self.body.source.def_id().expect_local()) else { return; };
+            let Def(_, trait_res_defid) = trait_ref.path.res else { return; };
+            debug!(?generics_fn);
+            generics_fn.predicates.iter().for_each(|predicate| {
+                let BoundPredicate(
+                    WhereBoundPredicate {
+                        span: bounded_span,
+                        bounded_ty,
+                        bounds,
+                        ..
+                    }
+                ) = predicate else { return; };
+                bounds.iter().for_each(|bd| {
+                    if let Trait(PolyTraitRef { trait_ref: tr_ref, .. }, _) = bd
+                        && let Def(_, res_defid) = tr_ref.path.res
+                        && res_defid == trait_res_defid // trait id matches
+                        && let TyKind::Path(Resolved(_, path)) = bounded_ty.kind
+                        && let Def(_, defid) = path.res
+                        && generics_fn.params
+                            .iter()
+                            .rfind(|param| param.def_id.to_def_id() == defid)
+                            .is_some() {
+                            suggestions.push((bounded_span.shrink_to_hi(), format!(" + 'static")));
+                        }
+                });
+            });
+        });
+        if suggestions.len() > 0 {
+            suggestions.dedup();
+            diag.multipart_suggestion_verbose(
+                format!("consider restricting the type parameter to the `'static` lifetime"),
+                suggestions,
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
     /// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`.
     pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
         // Iterate through all the errors, producing a diagnostic for each one. The diagnostics are
@@ -223,12 +323,21 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
                         // to report it; we could probably handle it by
                         // iterating over the universal regions and reporting
                         // an error that multiple bounds are required.
-                        self.buffer_error(self.infcx.tcx.sess.create_err(
-                            GenericDoesNotLiveLongEnough {
+                        let mut diag =
+                            self.infcx.tcx.sess.create_err(GenericDoesNotLiveLongEnough {
                                 kind: type_test.generic_kind.to_string(),
                                 span: type_test_span,
-                            },
-                        ));
+                            });
+
+                        // Add notes and suggestions for the case of 'static lifetime
+                        // implied but not specified when a generic associated types
+                        // are from higher-ranked trait bounds
+                        self.suggest_static_lifetime_for_gat_from_hrtb(
+                            &mut diag,
+                            type_test.lower_bound,
+                        );
+
+                        self.buffer_error(diag);
                     }
                 }
 
@@ -704,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
@@ -730,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 6fd9290058c36383e1a5c155de33f467701ee93d..6217676d5c150f5f977ff22735f65ca1d817a86f 100644 (file)
@@ -91,7 +91,8 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                     LocalMutationIsAllowed::Yes,
                 );
             }
-            StatementKind::Nop
+            StatementKind::ConstEvalCounter
+            | StatementKind::Nop
             | StatementKind::Retag { .. }
             | StatementKind::Deinit(..)
             | StatementKind::SetDiscriminant { .. } => {
index 278ffed07477b5b3bdf8224a7b3c79c89b2b9ace..bc81abe4005c919467114d502173cf017e0ab308 100644 (file)
@@ -5,6 +5,7 @@
 #![feature(let_chains)]
 #![feature(min_specialization)]
 #![feature(never_type)]
+#![feature(once_cell)]
 #![feature(rustc_attrs)]
 #![feature(stmt_expr_attributes)]
 #![feature(trusted_step)]
@@ -39,6 +40,7 @@
 
 use either::Either;
 use smallvec::SmallVec;
+use std::cell::OnceCell;
 use std::cell::RefCell;
 use std::collections::BTreeMap;
 use std::rc::Rc;
@@ -333,7 +335,7 @@ fn do_mir_borrowck<'tcx>(
                 used_mut: Default::default(),
                 used_mut_upvars: SmallVec::new(),
                 borrow_set: Rc::clone(&borrow_set),
-                dominators: Dominators::dummy(), // not used
+                dominators: Default::default(),
                 upvars: Vec::new(),
                 local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
                 region_names: RefCell::default(),
@@ -346,8 +348,6 @@ fn do_mir_borrowck<'tcx>(
         };
     }
 
-    let dominators = body.basic_blocks.dominators();
-
     let mut mbcx = MirBorrowckCtxt {
         infcx,
         param_env,
@@ -364,7 +364,7 @@ fn do_mir_borrowck<'tcx>(
         used_mut: Default::default(),
         used_mut_upvars: SmallVec::new(),
         borrow_set: Rc::clone(&borrow_set),
-        dominators,
+        dominators: Default::default(),
         upvars,
         local_names,
         region_names: RefCell::default(),
@@ -534,7 +534,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
     borrow_set: Rc<BorrowSet<'tcx>>,
 
     /// Dominators for MIR
-    dominators: Dominators<BasicBlock>,
+    dominators: OnceCell<Dominators<BasicBlock>>,
 
     /// Information about upvars not necessarily preserved in types or MIR
     upvars: Vec<Upvar<'tcx>>,
@@ -609,7 +609,8 @@ fn visit_statement_before_primary_effect(
             StatementKind::AscribeUserType(..)
             // Doesn't have any language semantics
             | StatementKind::Coverage(..)
-            // Does not actually affect borrowck
+            // These do not actually affect borrowck
+            | StatementKind::ConstEvalCounter
             | StatementKind::StorageLive(..) => {}
             StatementKind::StorageDead(local) => {
                 self.access_place(
@@ -1051,7 +1052,7 @@ fn check_access_for_conflict(
 
                 (Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => {
                     // Reading from mere reservations of mutable-borrows is OK.
-                    if !is_active(&this.dominators, borrow, location) {
+                    if !is_active(this.dominators(), borrow, location) {
                         assert!(allow_two_phase_borrow(borrow.kind));
                         return Control::Continue;
                     }
@@ -2173,7 +2174,7 @@ fn is_mutable(
                                     // `self.foo` -- we want to double
                                     // check that the location `*self`
                                     // is mutable (i.e., this is not a
-                                    // `Fn` closure).  But if that
+                                    // `Fn` closure). But if that
                                     // check succeeds, we want to
                                     // *blame* the mutability on
                                     // `place` (that is,
@@ -2219,6 +2220,10 @@ fn is_mutable(
     fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<Field> {
         path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
     }
+
+    fn dominators(&self) -> &Dominators<BasicBlock> {
+        self.dominators.get_or_init(|| self.body.basic_blocks.dominators())
+    }
 }
 
 mod error {
index b63e286676ff48fc2129344547850f320da554d0..4af324f740aef686c98d68bd329660555744bae2 100644 (file)
@@ -109,7 +109,7 @@ impl<'tcx, R1> MemberConstraintSet<'tcx, R1>
     R1: Copy + Hash + Eq,
 {
     /// Remap the "member region" key using `map_fn`, producing a new
-    /// member constraint set.  This is used in the NLL code to map from
+    /// member constraint set. This is used in the NLL code to map from
     /// the original `RegionVid` to an scc index. In some cases, we
     /// may have multiple `R1` values mapping to the same `R2` key -- that
     /// is ok, the two sets will be merged.
@@ -158,7 +158,7 @@ pub(crate) fn all_indices(
     }
 
     /// Iterate down the constraint indices associated with a given
-    /// peek-region.  You can then use `choice_regions` and other
+    /// peek-region. You can then use `choice_regions` and other
     /// methods to access data.
     pub(crate) fn indices(
         &self,
index e379e6470623759eabab4567b6d8de519713ba92..b2d92d0dba7a4de1cb38292dc7e9cb545f880d86 100644 (file)
@@ -385,7 +385,7 @@ pub(super) fn dump_annotation<'tcx>(
 
     // When the enclosing function is tagged with `#[rustc_regions]`,
     // we dump out various bits of state as warnings. This is useful
-    // for verifying that the compiler is behaving as expected.  These
+    // for verifying that the compiler is behaving as expected. These
     // warnings focus on the closure region requirements -- for
     // viewing the intraprocedural state, the -Zdump-mir output is
     // better.
index 9f6b1fdfcb54085853bb49c34a070b95c3358ec7..85d207b2fc9a7530afd0724e001c6881d6389eab 100644 (file)
@@ -63,7 +63,7 @@ fn ignore_borrow(
                     ty::RawPtr(..) | ty::Ref(_, _, hir::Mutability::Not) => {
                         // For both derefs of raw pointers and `&T`
                         // references, the original path is `Copy` and
-                        // therefore not significant.  In particular,
+                        // therefore not significant. In particular,
                         // there is nothing the user can do to the
                         // original path that would invalidate the
                         // newly created reference -- and if there
index 89ac0dfa4d6f51c2e61225b7d27b8fda4895bb57..918fb2d69237e4cb48b125a85daab2a60f8635dc 100644 (file)
@@ -209,7 +209,7 @@ fn place_components_conflict<'tcx>(
             match (elem, &base_ty.kind(), access) {
                 (_, _, Shallow(Some(ArtificialField::ArrayLength)))
                 | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
-                    // The array length is like  additional fields on the
+                    // The array length is like additional fields on the
                     // type; it does not overlap any existing data there.
                     // Furthermore, if cannot actually be a prefix of any
                     // borrowed place (at least in MIR as it is currently.)
index 308f6e19a73e86b2277985a092a5748a77827bd2..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};
@@ -527,6 +526,14 @@ pub(crate) fn region_value_str(&self, r: RegionVid) -> String {
         self.scc_values.region_value_str(scc)
     }
 
+    pub(crate) fn placeholders_contained_in<'a>(
+        &'a self,
+        r: RegionVid,
+    ) -> impl Iterator<Item = ty::PlaceholderRegion> + 'a {
+        let scc = self.constraint_sccs.scc(r.to_region_vid());
+        self.scc_values.placeholders_contained_in(scc)
+    }
+
     /// Returns access to the value of `r` for debugging purposes.
     pub(crate) fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex {
         let scc = self.constraint_sccs.scc(r.to_region_vid());
@@ -680,7 +687,7 @@ fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) {
     /// enforce the constraint).
     ///
     /// The current value of `scc` at the time the method is invoked
-    /// is considered a *lower bound*.  If possible, we will modify
+    /// is considered a *lower bound*. If possible, we will modify
     /// the constraint to set it equal to one of the option regions.
     /// If we make any changes, returns true, else false.
     #[instrument(skip(self, member_constraint_index), level = "debug")]
@@ -959,7 +966,7 @@ fn try_promote_type_test(
             //
             // This is needed because -- particularly in the case
             // where `ur` is a local bound -- we are sometimes in a
-            // position to prove things that our caller cannot.  See
+            // position to prove things that our caller cannot. See
             // #53570 for an example.
             if self.eval_verify_bound(infcx, param_env, generic_ty, ur, &type_test.verify_bound) {
                 continue;
@@ -2014,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,
             })
@@ -2035,7 +2042,7 @@ pub(crate) fn best_blame_constraint(
         //    '5: '6 ('6 is the target)
         //
         // Some of those regions are unified with `'6` (in the same
-        // SCC).  We want to screen those out. After that point, the
+        // SCC). We want to screen those out. After that point, the
         // "closest" constraint we have to the end is going to be the
         // most likely to be the point where the value escapes -- but
         // we still want to screen for an "interesting" point to
index 767f9fe39c68b7162092c6b53e2cb00383373a84..e0e814cfc0ac812e94655a920a909da4809555bb 100644 (file)
@@ -12,6 +12,8 @@
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::ObligationCtxt;
 
+use crate::session_diagnostics::NonGenericOpaqueTypeParam;
+
 use super::RegionInferenceContext;
 
 impl<'tcx> RegionInferenceContext<'tcx> {
@@ -235,7 +237,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
     /// # Parameters
     ///
     /// - `def_id`, the `impl Trait` type
-    /// - `substs`, the substs  used to instantiate this opaque type
+    /// - `substs`, the substs used to instantiate this opaque type
     /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
     ///   `opaque_defn.concrete_ty`
     #[instrument(level = "debug", skip(self))]
@@ -250,7 +252,7 @@ fn infer_opaque_definition_from_instantiation(
         }
 
         let definition_ty = instantiated_ty
-            .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false, origin)
+            .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
             .ty;
 
         if !check_opaque_type_parameter_valid(
@@ -271,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 =
@@ -288,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,
@@ -296,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,
@@ -307,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,
         ));
@@ -366,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(_))
             }
@@ -389,17 +378,13 @@ fn check_opaque_type_parameter_valid(
         } else {
             // Prevent `fn foo() -> Foo<u32>` from being defining.
             let opaque_param = opaque_generics.param_at(i, tcx);
-            tcx.sess
-                .struct_span_err(span, "non-defining opaque type use in defining scope")
-                .span_note(
-                    tcx.def_span(opaque_param.def_id),
-                    &format!(
-                        "used non-generic {} `{}` for generic parameter",
-                        opaque_param.kind.descr(),
-                        arg,
-                    ),
-                )
-                .emit();
+            let kind = opaque_param.kind.descr();
+            tcx.sess.emit_err(NonGenericOpaqueTypeParam {
+                ty: arg,
+                kind,
+                span,
+                param_span: tcx.def_span(opaque_param.def_id),
+            });
             return false;
         }
     }
index 577332c0744b84dd8447af7ab3519a33ef18abe0..23acf159240fa7bf509b44ee9683a6bac6acd87c 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_errors::{IntoDiagnosticArg, MultiSpan};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{GenericArg, Ty};
 use rustc_span::Span;
 
 use crate::diagnostics::RegionName;
@@ -240,3 +240,14 @@ pub(crate) struct MoveBorrow<'a> {
     #[label]
     pub borrow_span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(borrowck_opaque_type_non_generic_param, code = "E0792")]
+pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
+    pub ty: GenericArg<'tcx>,
+    pub kind: &'a str,
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub param_span: Span,
+}
index 02222c0a03cb350f9dcfdebc2b963db3f1edfcd5..11729e2c83f0b9d098788e495a6db5ea5b271ce5 100644 (file)
@@ -107,11 +107,7 @@ pub(super) fn normalize_and_prove_instantiated_predicates(
         instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
         locations: Locations,
     ) {
-        for (predicate, span) in instantiated_predicates
-            .predicates
-            .into_iter()
-            .zip(instantiated_predicates.spans.into_iter())
-        {
+        for (predicate, span) in instantiated_predicates {
             debug!(?predicate);
             let category = ConstraintCategory::Predicate(span);
             let predicate = self.normalize_with_category(predicate, locations, category);
index ce7f857e27310aa64b01f6d2529c08cd96ff00de..e15d1b99ad205229e2d7b901e101da1bcc5614b5 100644 (file)
@@ -107,7 +107,7 @@ pub fn apply_closure_requirements(
         closure_substs: ty::SubstsRef<'tcx>,
     ) {
         // Extract the values of the free regions in `closure_substs`
-        // into a vector.  These are the regions that we will be
+        // into a vector. These are the regions that we will be
         // relating to one another.
         let closure_mapping = &UniversalRegions::closure_mapping(
             self.tcx,
index 09cf870bcf35af780f724bdb8a4ea55a6fca3ccd..82ff862479e81824e1f47c6606e6b54cca6e6c86 100644 (file)
@@ -98,7 +98,7 @@ pub(crate) fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
         let upper_bounds = self.non_local_upper_bounds(fr);
 
         // In case we find more than one, reduce to one for
-        // convenience.  This is to prevent us from generating more
+        // convenience. This is to prevent us from generating more
         // complex constraints, but it will cause spurious errors.
         let post_dom = self.inverse_outlives.mutual_immediate_postdominator(upper_bounds);
 
@@ -128,7 +128,7 @@ pub(crate) fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
         let lower_bounds = self.non_local_bounds(&self.outlives, fr);
 
         // In case we find more than one, reduce to one for
-        // convenience.  This is to prevent us from generating more
+        // convenience. This is to prevent us from generating more
         // complex constraints, but it will cause spurious errors.
         let post_dom = self.outlives.mutual_immediate_postdominator(lower_bounds);
 
@@ -359,14 +359,9 @@ fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
                         .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
                 }
 
-                OutlivesBound::RegionSubProjection(r_a, projection_b) => {
+                OutlivesBound::RegionSubAlias(r_a, alias_b) => {
                     self.region_bound_pairs
-                        .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
-                }
-
-                OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
-                    self.region_bound_pairs
-                        .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
+                        .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
                 }
             }
         }
index 42b577175e43757b77357854e6a6047cf0a7f5d7..3ff5d188a3d35233cf381cfb460655ee6b62c3ca 100644 (file)
@@ -328,7 +328,7 @@ fn compute_drop_live_points_for_block(&mut self, mpi: MovePathIndex, term_point:
         debug_assert!(self.drop_live_at.contains(term_point));
 
         // Otherwise, scan backwards through the statements in the
-        // block.  One of them may be either a definition or use
+        // block. One of them may be either a definition or use
         // live point.
         let term_location = self.cx.elements.to_location(term_point);
         debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,);
index 7a3db191f0c66eef0436ae8844e9ca6e5e33c3cb..06087b0c579d8c293349d82e0e847fb5a2b50da5 100644 (file)
@@ -1258,6 +1258,7 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo
             | StatementKind::StorageDead(..)
             | StatementKind::Retag { .. }
             | StatementKind::Coverage(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
             StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
                 bug!("Statement not allowed in this MIR phase")
@@ -1665,7 +1666,7 @@ fn check_local(&mut self, body: &Body<'tcx>, local: Local, local_decl: &LocalDec
     fn ensure_place_sized(&mut self, ty: Ty<'tcx>, span: Span) {
         let tcx = self.tcx();
 
-        // Erase the regions from `ty` to get a global type.  The
+        // Erase the regions from `ty` to get a global type. The
         // `Sized` bound in no way depends on precise regions, so this
         // shouldn't affect `is_sized`.
         let erased_ty = tcx.erase_regions(ty);
index a4a0c5b90fed32d2a20372aa908806b81aa9a2fe..5380913f5c86ae5a4ab4fc06ee422b6ea553cbee 100644 (file)
@@ -162,7 +162,7 @@ struct UniversalRegionIndices<'tcx> {
     /// `ty::Region` to the internal `RegionVid` we are using. This is
     /// used because trait matching and type-checking will feed us
     /// region constraints that reference those regions and we need to
-    /// be able to map them our internal `RegionVid`. This is
+    /// be able to map them to our internal `RegionVid`. This is
     /// basically equivalent to an `InternalSubsts`, except that it also
     /// contains an entry for `ReStatic` -- it might be nice to just
     /// use a substs, and then handle `ReStatic` another way.
@@ -472,7 +472,7 @@ fn build(self) -> UniversalRegions<'tcx> {
         // C-variadic fns also have a `VaList` input that's not listed in the signature
         // (as it's created inside the body itself, not passed in from outside).
         if let DefiningTy::FnDef(def_id, _) = defining_ty {
-            if self.infcx.tcx.fn_sig(def_id).c_variadic() {
+            if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() {
                 let va_list_did = self.infcx.tcx.require_lang_item(
                     LangItem::VaList,
                     Some(self.infcx.tcx.def_span(self.mir_def.did)),
@@ -637,7 +637,7 @@ fn compute_inputs_and_output(
                 let closure_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap();
 
                 // The "inputs" of the closure in the
-                // signature appear as a tuple.  The MIR side
+                // signature appear as a tuple. The MIR side
                 // flattens this tuple.
                 let (&output, tuplized_inputs) =
                     inputs_and_output.skip_binder().split_last().unwrap();
@@ -665,7 +665,7 @@ fn compute_inputs_and_output(
             }
 
             DefiningTy::FnDef(def_id, _) => {
-                let sig = tcx.fn_sig(def_id);
+                let sig = tcx.fn_sig(def_id).subst_identity();
                 let sig = indices.fold_to_region_vids(tcx, sig);
                 sig.inputs_and_output()
             }
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 d59b3b8c86d35ef6303bb8a3adbd5e9aecf2d1f1..ef5a75f428d4e979c8582c5708c79a8c9854180e 100644 (file)
@@ -20,7 +20,7 @@ pub fn expand_deriving_clone(
     // some additional `AssertParamIsClone` assertions.
     //
     // We can use the simple form if either of the following are true.
-    // - The type derives Copy and there are no generic parameters.  (If we
+    // - The type derives Copy and there are no generic parameters. (If we
     //   used the simple form with generics, we'd have to bound the generics
     //   with Clone + Copy, and then there'd be no Clone impl at all if the
     //   user fills in something that is Clone but not Copy. After
@@ -82,7 +82,7 @@ pub fn expand_deriving_clone(
             nonself_args: Vec::new(),
             ret_ty: Self_,
             attributes: attrs,
-            unify_fieldless_variants: false,
+            fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
             combine_substructure: substructure,
         }],
         associated_types: Vec::new(),
@@ -177,7 +177,9 @@ fn cs_clone(
             all_fields = af;
             vdata = &variant.data;
         }
-        EnumTag(..) => cx.span_bug(trait_span, &format!("enum tags in `derive({})`", name,)),
+        EnumTag(..) | AllFieldlessEnum(..) => {
+            cx.span_bug(trait_span, &format!("enum tags in `derive({})`", name,))
+        }
         StaticEnum(..) | StaticStruct(..) => {
             cx.span_bug(trait_span, &format!("associated function in `derive({})`", name))
         }
index f861d47ed408e45fc02ecc6e7c75f76357d47a83..3e994f037ad7aa7e2843b0a271257b679bbab3e4 100644 (file)
@@ -36,7 +36,7 @@ pub fn expand_deriving_eq(
             nonself_args: vec![],
             ret_ty: Unit,
             attributes: attrs,
-            unify_fieldless_variants: true,
+            fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 cs_total_eq_assert(a, b, c)
             })),
index 96d18c7afb924c56a6fb6d949a414cbfead310ae..a926fca4e65f8ac21fe7eabd06a1c260d5c0b474 100644 (file)
@@ -29,7 +29,7 @@ pub fn expand_deriving_ord(
             nonself_args: vec![(self_ref(), sym::other)],
             ret_ty: Path(path_std!(cmp::Ordering)),
             attributes: attrs,
-            unify_fieldless_variants: true,
+            fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
             combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))),
         }],
         associated_types: Vec::new(),
index 7f95551fc483a6bd69c4386a30191617581ec77e..9051fe0b28abec750146a6435e0b50c021e99d6f 100644 (file)
@@ -76,7 +76,7 @@ fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOr
         nonself_args: vec![(self_ref(), sym::other)],
         ret_ty: Path(path_local!(bool)),
         attributes: attrs,
-        unify_fieldless_variants: true,
+        fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
         combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))),
     }];
 
index 5c4e5b7f8167500c1fd16a51b43d2a099e6548f5..2fc30d8e05f2c6748c4e03ed0a07d056105e3439 100644 (file)
@@ -1,7 +1,7 @@
 use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::{path_std, pathvec_std};
-use rustc_ast::MetaItem;
+use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -21,6 +21,27 @@ pub fn expand_deriving_partial_ord(
 
     let attrs = thin_vec![cx.attr_word(sym::inline, span)];
 
+    // Order in which to perform matching
+    let tag_then_data = if let Annotatable::Item(item) = item
+        && let ItemKind::Enum(def, _) = &item.kind {
+            let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect();
+            match dataful.iter().filter(|&&b| b).count() {
+                // No data, placing the tag check first makes codegen simpler
+                0 => true,
+                1..=2 => false,
+                _ => {
+                    (0..dataful.len()-1).any(|i| {
+                        if dataful[i] && let Some(idx) = dataful[i+1..].iter().position(|v| *v) {
+                            idx >= 2
+                        } else {
+                            false
+                        }
+                    })
+                }
+            }
+        } else {
+            true
+        };
     let partial_cmp_def = MethodDef {
         name: sym::partial_cmp,
         generics: Bounds::empty(),
@@ -28,9 +49,9 @@ pub fn expand_deriving_partial_ord(
         nonself_args: vec![(self_ref(), sym::other)],
         ret_ty,
         attributes: attrs,
-        unify_fieldless_variants: true,
+        fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
         combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
-            cs_partial_cmp(cx, span, substr)
+            cs_partial_cmp(cx, span, substr, tag_then_data)
         })),
     };
 
@@ -47,7 +68,12 @@ pub fn expand_deriving_partial_ord(
     trait_def.expand(cx, mitem, item, push)
 }
 
-pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
+fn cs_partial_cmp(
+    cx: &mut ExtCtxt<'_>,
+    span: Span,
+    substr: &Substructure<'_>,
+    tag_then_data: bool,
+) -> BlockOrExpr {
     let test_id = Ident::new(sym::cmp, span);
     let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
     let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
@@ -74,12 +100,50 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
                 let args = vec![field.self_expr.clone(), other_expr.clone()];
                 cx.expr_call_global(field.span, partial_cmp_path.clone(), args)
             }
-            CsFold::Combine(span, expr1, expr2) => {
-                let eq_arm =
-                    cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1);
-                let neq_arm =
-                    cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
-                cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
+            CsFold::Combine(span, mut expr1, expr2) => {
+                // When the item is an enum, this expands to
+                // ```
+                // match (expr2) {
+                //     Some(Ordering::Equal) => expr1,
+                //     cmp => cmp
+                // }
+                // ```
+                // where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match`
+                //  against the enum variants. This means that we begin by comparing the enum tags,
+                // before either inspecting their contents (if they match), or returning
+                // the `cmp::Ordering` of comparing the enum tags.
+                // ```
+                // match partial_cmp(self_tag, other_tag) {
+                //     Some(Ordering::Equal) => match (self, other)  {
+                //         (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
+                //         (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0),
+                //         _ => Some(Ordering::Equal)
+                //     }
+                //     cmp => cmp
+                // }
+                // ```
+                // If we have any certain enum layouts, flipping this results in better codegen
+                // ```
+                // match (self, other) {
+                //     (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
+                //     _ => partial_cmp(self_tag, other_tag)
+                // }
+                // ```
+                // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354
+
+                if !tag_then_data
+                    && let ExprKind::Match(_, arms) = &mut expr1.kind
+                    && let Some(last) = arms.last_mut()
+                    && let PatKind::Wild = last.pat.kind {
+                        last.body = expr2;
+                        expr1
+                } else {
+                    let eq_arm =
+                        cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1);
+                    let neq_arm =
+                        cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
+                    cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
+                }
             }
             CsFold::Fieldless => cx.expr_some(span, cx.expr_path(equal_path.clone())),
         },
index 5b1b7e6804c86d7235d0597e074901dba8fa0b37..e0f487e864898d72d530efd0d1b1b0815d01894d 100644 (file)
@@ -2,6 +2,7 @@
 use crate::deriving::generic::*;
 use crate::deriving::path_std;
 
+use ast::EnumDef;
 use rustc_ast::{self as ast, MetaItem};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -31,7 +32,8 @@ pub fn expand_deriving_debug(
             nonself_args: vec![(fmtr, sym::f)],
             ret_ty: Path(path_std!(fmt::Result)),
             attributes: ast::AttrVec::new(),
-            unify_fieldless_variants: false,
+            fieldless_variants_strategy:
+                FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 show_substructure(a, b, c)
             })),
@@ -43,16 +45,18 @@ pub fn expand_deriving_debug(
 }
 
 fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
+    // We want to make sure we have the ctxt set so that we can use unstable methods
+    let span = cx.with_def_site_ctxt(span);
+
     let (ident, vdata, fields) = match substr.fields {
         Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
         EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
+        AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr),
         EnumTag(..) | StaticStruct(..) | StaticEnum(..) => {
             cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
         }
     };
 
-    // We want to make sure we have the ctxt set so that we can use unstable methods
-    let span = cx.with_def_site_ctxt(span);
     let name = cx.expr_str(span, ident.name);
     let fmt = substr.nonselflike_args[0].clone();
 
@@ -173,3 +177,47 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
         BlockOrExpr::new_mixed(stmts, Some(expr))
     }
 }
+
+/// Special case for enums with no fields. Builds:
+/// ```text
+/// impl ::core::fmt::Debug for A {
+///     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+///          ::core::fmt::Formatter::write_str(f,
+///             match self {
+///                 A::A => "A",
+///                 A::B() => "B",
+///                 A::C {} => "C",
+///             })
+///     }
+/// }
+/// ```
+fn show_fieldless_enum(
+    cx: &mut ExtCtxt<'_>,
+    span: Span,
+    def: &EnumDef,
+    substr: &Substructure<'_>,
+) -> BlockOrExpr {
+    let fmt = substr.nonselflike_args[0].clone();
+    let arms = def
+        .variants
+        .iter()
+        .map(|v| {
+            let variant_path = cx.path(span, vec![substr.type_ident, v.ident]);
+            let pat = match &v.data {
+                ast::VariantData::Tuple(fields, _) => {
+                    debug_assert!(fields.is_empty());
+                    cx.pat_tuple_struct(span, variant_path, vec![])
+                }
+                ast::VariantData::Struct(fields, _) => {
+                    debug_assert!(fields.is_empty());
+                    cx.pat_struct(span, variant_path, vec![])
+                }
+                ast::VariantData::Unit(_) => cx.pat_path(span, variant_path),
+            };
+            cx.arm(span, pat, cx.expr_str(span, v.ident.name))
+        })
+        .collect::<Vec<_>>();
+    let name = cx.expr_match(span, cx.expr_self(span), arms);
+    let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
+    BlockOrExpr::new_expr(cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]))
+}
index 62af02c2bb4b2d35304cf4eafd42036fba31d5ef..5f9519dad1b25e91213e145a4ec768cc376f5d01 100644 (file)
@@ -49,7 +49,7 @@ pub fn expand_deriving_rustc_decodable(
                 PathKind::Std,
             )),
             attributes: ast::AttrVec::new(),
-            unify_fieldless_variants: false,
+            fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 decodable_substructure(a, b, c, krate)
             })),
index eb66c4a69a69bc25bab4126e1649d5f3097a940f..18270747296b8f7c7d8762e141f7c8df88da5f36 100644 (file)
@@ -34,7 +34,7 @@ pub fn expand_deriving_default(
             nonself_args: Vec::new(),
             ret_ty: Self_,
             attributes: attrs,
-            unify_fieldless_variants: false,
+            fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
             combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| {
                 match substr.fields {
                     StaticStruct(_, fields) => {
index 68bc0ff2ec0b41c553339586a0874ef5fcb6a1f1..2afeed927ac2c7664d8e941f211f7c3f3bccff74 100644 (file)
@@ -133,7 +133,7 @@ pub fn expand_deriving_rustc_encodable(
                 PathKind::Std,
             )),
             attributes: AttrVec::new(),
-            unify_fieldless_variants: false,
+            fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 encodable_substructure(a, b, c, krate)
             })),
index beac591bfc879065a2c6fd411be0673ba59a3383..17b7ac0eba1209de55bddbee1ba6087945b409ed 100644 (file)
@@ -222,14 +222,27 @@ pub struct MethodDef<'a> {
 
     pub attributes: ast::AttrVec,
 
-    /// Can we combine fieldless variants for enums into a single match arm?
-    /// If true, indicates that the trait operation uses the enum tag in some
-    /// way.
-    pub unify_fieldless_variants: bool,
+    pub fieldless_variants_strategy: FieldlessVariantsStrategy,
 
     pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
 }
 
+/// How to handle fieldless enum variants.
+#[derive(PartialEq)]
+pub enum FieldlessVariantsStrategy {
+    /// Combine fieldless variants into a single match arm.
+    /// This assumes that relevant information has been handled
+    /// by looking at the enum's discriminant.
+    Unify,
+    /// Don't do anything special about fieldless variants. They are
+    /// handled like any other variant.
+    Default,
+    /// If all variants of the enum are fieldless, expand the special
+    /// `AllFieldLessEnum` substructure, so that the entire enum can be handled
+    /// at once.
+    SpecializeIfAllVariantsFieldless,
+}
+
 /// All the data about the data structure/method being derived upon.
 pub struct Substructure<'a> {
     /// ident of self
@@ -264,9 +277,14 @@ pub enum StaticFields {
 
 /// A summary of the possible sets of fields.
 pub enum SubstructureFields<'a> {
-    /// A non-static method with `Self` is a struct.
+    /// A non-static method where `Self` is a struct.
     Struct(&'a ast::VariantData, Vec<FieldInfo>),
 
+    /// A non-static method handling the entire enum at once
+    /// (after it has been determined that none of the enum
+    /// variants has any fields).
+    AllFieldlessEnum(&'a ast::EnumDef),
+
     /// Matching variants of the enum: variant index, variant count, ast::Variant,
     /// fields: the field name is only non-`None` in the case of a struct
     /// variant.
@@ -1086,8 +1104,8 @@ fn expand_static_struct_method_body(
     /// ```
     /// Creates a tag check combined with a match for a tuple of all
     /// `selflike_args`, with an arm for each variant with fields, possibly an
-    /// arm for each fieldless variant (if `!unify_fieldless_variants` is not
-    /// true), and possibly a default arm.
+    /// arm for each fieldless variant (if `unify_fieldless_variants` is not
+    /// `Unify`), and possibly a default arm.
     fn expand_enum_method_body<'b>(
         &self,
         cx: &mut ExtCtxt<'_>,
@@ -1101,7 +1119,8 @@ fn expand_enum_method_body<'b>(
         let variants = &enum_def.variants;
 
         // Traits that unify fieldless variants always use the tag(s).
-        let uses_tags = self.unify_fieldless_variants;
+        let unify_fieldless_variants =
+            self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify;
 
         // There is no sensible code to be generated for *any* deriving on a
         // zero-variant enum. So we just generate a failing expression.
@@ -1161,23 +1180,35 @@ fn expand_enum_method_body<'b>(
         // match is necessary.
         let all_fieldless = variants.iter().all(|v| v.data.fields().is_empty());
         if all_fieldless {
-            if uses_tags && variants.len() > 1 {
-                // If the type is fieldless and the trait uses the tag and
-                // there are multiple variants, we need just an operation on
-                // the tag(s).
-                let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
-                let mut tag_check = self.call_substructure_method(
-                    cx,
-                    trait_,
-                    type_ident,
-                    nonselflike_args,
-                    &EnumTag(tag_field, None),
-                );
-                tag_let_stmts.append(&mut tag_check.0);
-                return BlockOrExpr(tag_let_stmts, tag_check.1);
-            }
-
-            if variants.len() == 1 {
+            if variants.len() > 1 {
+                match self.fieldless_variants_strategy {
+                    FieldlessVariantsStrategy::Unify => {
+                        // If the type is fieldless and the trait uses the tag and
+                        // there are multiple variants, we need just an operation on
+                        // the tag(s).
+                        let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
+                        let mut tag_check = self.call_substructure_method(
+                            cx,
+                            trait_,
+                            type_ident,
+                            nonselflike_args,
+                            &EnumTag(tag_field, None),
+                        );
+                        tag_let_stmts.append(&mut tag_check.0);
+                        return BlockOrExpr(tag_let_stmts, tag_check.1);
+                    }
+                    FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => {
+                        return self.call_substructure_method(
+                            cx,
+                            trait_,
+                            type_ident,
+                            nonselflike_args,
+                            &AllFieldlessEnum(enum_def),
+                        );
+                    }
+                    FieldlessVariantsStrategy::Default => (),
+                }
+            } else if variants.len() == 1 {
                 // If there is a single variant, we don't need an operation on
                 // the tag(s). Just use the most degenerate result.
                 return self.call_substructure_method(
@@ -1187,7 +1218,7 @@ fn expand_enum_method_body<'b>(
                     nonselflike_args,
                     &EnumMatching(0, 1, &variants[0], Vec::new()),
                 );
-            };
+            }
         }
 
         // These arms are of the form:
@@ -1198,7 +1229,7 @@ fn expand_enum_method_body<'b>(
         let mut match_arms: Vec<ast::Arm> = variants
             .iter()
             .enumerate()
-            .filter(|&(_, v)| !(self.unify_fieldless_variants && v.data.fields().is_empty()))
+            .filter(|&(_, v)| !(unify_fieldless_variants && v.data.fields().is_empty()))
             .map(|(index, variant)| {
                 // A single arm has form (&VariantK, &VariantK, ...) => BodyK
                 // (see "Final wrinkle" note below for why.)
@@ -1249,7 +1280,7 @@ fn expand_enum_method_body<'b>(
         // Add a default arm to the match, if necessary.
         let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
         let default = match first_fieldless {
-            Some(v) if self.unify_fieldless_variants => {
+            Some(v) if unify_fieldless_variants => {
                 // We need a default case that handles all the fieldless
                 // variants. The index and actual variant aren't meaningful in
                 // this case, so just use dummy values.
@@ -1296,7 +1327,7 @@ fn expand_enum_method_body<'b>(
         // If the trait uses the tag and there are multiple variants, we need
         // to add a tag check operation before the match. Otherwise, the match
         // is enough.
-        if uses_tags && variants.len() > 1 {
+        if unify_fieldless_variants && variants.len() > 1 {
             let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
 
             // Combine a tag check with the match.
@@ -1580,5 +1611,6 @@ pub fn cs_fold<F>(
             }
         }
         StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
+        AllFieldlessEnum(..) => cx.span_bug(trait_span, "fieldless enum in `derive`"),
     }
 }
index c136bb7141ab9eef3f4b0896e20fc08a47816503..f8570d8f86a08dd691fe82dbd23c26518afcde24 100644 (file)
@@ -33,7 +33,7 @@ pub fn expand_deriving_hash(
             nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)],
             ret_ty: Unit,
             attributes: AttrVec::new(),
-            unify_fieldless_variants: true,
+            fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 hash_substructure(a, b, c)
             })),
index 84d06b69a9d976c3d7c260dfe723693139dfe80b..e5a5e606930f00e213c7bca7c893889955598892 100644 (file)
@@ -1,4 +1,4 @@
-// The compiler code necessary to support the env! extension.  Eventually this
+// The compiler code necessary to support the env! extension. Eventually this
 // should all get sucked into either the compiler syntax extension plugin
 // interface.
 //
index b2b7b9d75bd37163e9ac20a305ba9e19ac9366ef..e93a23394c03ff9b9f74ea87e72c6d1ef27ee539 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,
+    FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, 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.
@@ -437,7 +435,16 @@ enum ArgRef<'a> {
                     format_options: FormatOptions {
                         fill: format.fill,
                         alignment,
-                        flags: format.flags,
+                        sign: format.sign.map(|s| match s {
+                            parse::Sign::Plus => FormatSign::Plus,
+                            parse::Sign::Minus => FormatSign::Minus,
+                        }),
+                        alternate: format.alternate,
+                        zero_pad: format.zero_pad,
+                        debug_hex: format.debug_hex.map(|s| match s {
+                            parse::DebugHex::Lower => FormatDebugHex::Lower,
+                            parse::DebugHex::Upper => FormatDebugHex::Upper,
+                        }),
                         precision,
                         width,
                     },
@@ -583,7 +590,7 @@ fn report_missing_placeholders(
     if detect_foreign_fmt {
         use super::format_foreign as foreign;
 
-        // The set of foreign substitutions we've explained.  This prevents spamming the user
+        // The set of foreign substitutions we've explained. This prevents spamming the user
         // with `%d should be written as {}` over and over again.
         let mut explained = FxHashSet::default();
 
@@ -850,7 +857,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 6f7fc3a95ba640e21311aca2d37b403f0f25a2c4..bd9e903b6ba297cdda9ce8de7efa4404e6c4325d 100644 (file)
@@ -253,7 +253,7 @@ pub fn translate(&self) -> Result<String, Option<String>> {
     #[derive(Copy, Clone, PartialEq, Debug)]
     pub enum Num {
         // The range of these values is technically bounded by `NL_ARGMAX`... but, at least for GNU
-        // libc, it apparently has no real fixed limit.  A `u16` is used here on the basis that it
+        // libc, it apparently has no real fixed limit. A `u16` is used here on the basis that it
         // is *vanishingly* unlikely that *anyone* is going to try formatting something wider, or
         // with more precision, than 32 thousand positions which is so wide it couldn't possibly fit
         // on a screen.
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..dffb2ed8f4f392544f5d551d1ea7105c853e55db 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>(
@@ -789,6 +794,7 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
         StatementKind::StorageLive(_)
         | StatementKind::StorageDead(_)
         | StatementKind::Deinit(_)
+        | StatementKind::ConstEvalCounter
         | StatementKind::Nop
         | StatementKind::FakeRead(..)
         | StatementKind::Retag { .. }
@@ -932,7 +938,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 +976,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);
index dee6fb5b5130d1f27abaf1fda1581605a82973b5..49c4f1aaaefc69a9e52a68792f55f76b68471281 100644 (file)
@@ -304,7 +304,7 @@ fn data_id_for_static(
 
         // Comment copied from https://github.com/rust-lang/rust/blob/45060c2a66dfd667f88bd8b94261b28a58d85bd5/src/librustc_codegen_llvm/consts.rs#L141
         // Declare an internal global `extern_with_linkage_foo` which
-        // is initialized with the address of `foo`.  If `foo` is
+        // is initialized with the address of `foo`. If `foo` is
         // discarded during linking (for example, if `foo` has weak
         // linkage and there are no definitions), then
         // `extern_with_linkage_foo` will instead be initialized to
@@ -530,6 +530,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
                         | StatementKind::Retag(_, _)
                         | StatementKind::AscribeUserType(_, _)
                         | StatementKind::Coverage(_)
+                        | StatementKind::ConstEvalCounter
                         | StatementKind::Nop => {}
                     }
                 }
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 2ba012a77b0a908788f0272705f82f7c875cb1a7..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,18 +65,14 @@ 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
             .working_dir
             .to_string_lossy(FileNameDisplayPreference::Remapped)
             .into_owned();
-        let (name, file_info) = match tcx.sess.local_crate_source_file.clone() {
+        let (name, file_info) = match tcx.sess.local_crate_source_file() {
             Some(path) => {
                 let name = path.to_string_lossy().into_owned();
                 (name, None)
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..3e3b685713427ce13bb571354b00316c4d02943c 100644 (file)
@@ -46,7 +46,7 @@ fn create_entry_fn(
         is_main_fn: bool,
         sigpipe: u8,
     ) {
-        let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
+        let main_ret_ty = tcx.fn_sig(rust_main_def_id).no_bound_vars().unwrap().output();
         // Given that `main()` has no arguments,
         // then its return type cannot have
         // late-bound regions, since late-bound
@@ -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 546540dfd76232ad2b6d50887e1b9304d1f9e63d..28be6d033f8bf3d82c3731d60f7837e7d8760df1 100644 (file)
@@ -221,7 +221,7 @@ fn store(
                 bx.store(val, cast_dst, self.layout.align.abi);
             } else {
                 // The actual return type is a struct, but the ABI
-                // adaptation code has cast it into some scalar type.  The
+                // adaptation code has cast it into some scalar type. The
                 // code that follows is the only reliable way I have
                 // found to do a transform like i64 -> {i32,i32}.
                 // Basically we dump the data onto the stack then memcpy it.
index 606f710641fc0e25a17fd6f2b598058328a1e6b4..d9f8170a3cffa0617172e93f5d0d5d4a0038efdd 100644 (file)
@@ -445,7 +445,7 @@ pub(crate) fn inline_asm_call<'ll>(
             };
 
             // Store mark in a metadata node so we can map LLVM errors
-            // back to source locations.  See #17552.
+            // back to source locations. See #17552.
             let key = "srcloc";
             let kind = llvm::LLVMGetMDKindIDInContext(
                 bx.llcx,
@@ -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 95baa95b02183601ff022eaac84e1f3b9622ae07..54ac7a46cf2f331681ffb9f2e9b0e90034b94dcd 100644 (file)
@@ -441,7 +441,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
         // the WebAssembly specification, which has this feature. This won't be
         // needed when LLVM enables this `multivalue` feature by default.
         if !cx.tcx.is_closure(instance.def_id()) {
-            let abi = cx.tcx.fn_sig(instance.def_id()).abi();
+            let abi = cx.tcx.fn_sig(instance.def_id()).skip_binder().abi();
             if abi == Abi::Wasm {
                 function_features.push("+multivalue".to_string());
             }
index 36aba5bb740bd6120030c0cbf0e5d6654fa0afc8..58ca87524deb69d891cc1dbfe8c953de5cdc4b95 100644 (file)
@@ -15,8 +15,8 @@
 use crate::llvm::archive_ro::{ArchiveRO, Child};
 use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
 use rustc_codegen_ssa::back::archive::{
-    get_native_object_symbols, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder,
-    ArchiveBuilderBuilder, UnknownArchiveKind,
+    get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder,
+    ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind,
 };
 
 use rustc_session::cstore::DllImport;
@@ -66,7 +66,13 @@ fn add_archive(
         archive: &Path,
         skip: Box<dyn FnMut(&str) -> bool + 'static>,
     ) -> io::Result<()> {
-        let archive_ro = match ArchiveRO::open(archive) {
+        let mut archive = archive.to_path_buf();
+        if self.sess.target.llvm_target.contains("-apple-macosx") {
+            if let Some(new_archive) = try_extract_macho_fat_archive(&self.sess, &archive)? {
+                archive = new_archive
+            }
+        }
+        let archive_ro = match ArchiveRO::open(&archive) {
             Ok(ar) => ar,
             Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
         };
@@ -74,7 +80,7 @@ fn add_archive(
             return Ok(());
         }
         self.additions.push(Addition::Archive {
-            path: archive.to_path_buf(),
+            path: archive,
             archive: archive_ro,
             skip: Box::new(skip),
         });
@@ -102,7 +108,9 @@ fn build(mut self: Box<Self>, output: &Path) -> bool {
 
 impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
     fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> {
-        if sess.target.arch == "wasm32" || sess.target.arch == "wasm64" {
+        // FIXME use ArArchiveBuilder on most targets again once reading thin archives is
+        // implemented
+        if true || sess.target.arch == "wasm32" || sess.target.arch == "wasm64" {
             Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
         } else {
             Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols))
@@ -145,7 +153,7 @@ fn create_dll_import_lib(
             // The binutils linker used on -windows-gnu targets cannot read the import
             // libraries generated by LLVM: in our attempts, the linker produced an .EXE
             // that loaded but crashed with an AV upon calling one of the imported
-            // functions.  Therefore, use binutils to create the import library instead,
+            // functions. Therefore, use binutils to create the import library instead,
             // by writing a .DEF file to the temp dir and calling binutils's dlltool.
             let def_file_path =
                 tmpdir.join(format!("{}{}", lib_name, name_suffix)).with_extension("def");
@@ -219,7 +227,7 @@ fn create_dll_import_lib(
 
             // All import names are Rust identifiers and therefore cannot contain \0 characters.
             // FIXME: when support for #[link_name] is implemented, ensure that the import names
-            // still don't contain any \0 characters.  Also need to check that the names don't
+            // still don't contain any \0 characters. Also need to check that the names don't
             // contain substrings like " @" or "NONAME" that are keywords or otherwise reserved
             // in definition files.
             let cstring_import_name_and_ordinal_vector: Vec<(CString, Option<u16>)> =
@@ -433,7 +441,7 @@ fn find_binutils_dlltool(sess: &Session) -> OsString {
     }
 
     // The user didn't specify the location of the dlltool binary, and we weren't able
-    // to find the appropriate one on the PATH.  Just return the name of the tool
+    // to find the appropriate one on the PATH. Just return the name of the tool
     // and let the invocation fail with a hopefully useful error message.
     tool_name
 }
index e23c88b62c14b4bb92ff0be5078120a0e16ecc79..b2af9f31e4494175aad3d4140b32b7dd232247a5 100644 (file)
@@ -909,7 +909,7 @@ unsafe fn embed_bitcode(
 
 // Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
 // This is required to satisfy `dllimport` references to static data in .rlibs
-// when using MSVC linker.  We do this only for data, as linker can fix up
+// when using MSVC linker. We do this only for data, as linker can fix up
 // code references on its own.
 // See #26591, #27438
 fn create_msvc_imps(
index 5bf45a81e4347cd7de59a42a80fdaaa796131bd6..0f33b98548984877a230edeb0004e8ba403e7132 100644 (file)
@@ -501,7 +501,7 @@ fn scalar_load_metadata<'a, 'll, 'tcx>(
             layout: TyAndLayout<'tcx>,
             offset: Size,
         ) {
-            if !scalar.is_always_valid(bx) {
+            if !scalar.is_uninit_valid() {
                 bx.noundef_metadata(load);
             }
 
@@ -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 70ff5c9617b7a8c7c3ecdf008467d18eb924fb0d..f1d01a4602a5e313e06ff3ef816f42c2423a42a2 100644 (file)
@@ -49,8 +49,8 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
         let llptrty = fn_abi.ptr_to_llvm_type(cx);
 
         // This is subtle and surprising, but sometimes we have to bitcast
-        // the resulting fn pointer.  The reason has to do with external
-        // functions.  If you have two crates that both bind the same C
+        // the resulting fn pointer. The reason has to do with external
+        // functions. If you have two crates that both bind the same C
         // library, they may not use precisely the same types: for
         // example, they will probably each declare their own structs,
         // which are distinct types from LLVM's point of view (nominal
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 3626aa901c0ef45b02dfa23fe54487d491436f11..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),
@@ -140,7 +133,7 @@ pub fn codegen_static_initializer<'ll, 'tcx>(
 fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) {
     // The target may require greater alignment for globals than the type does.
     // Note: GCC and Clang also allow `__attribute__((aligned))` on variables,
-    // which can force it to be smaller.  Rust doesn't support this yet.
+    // which can force it to be smaller. Rust doesn't support this yet.
     if let Some(min) = cx.sess().target.min_global_align {
         match Align::from_bits(min) {
             Ok(min) => align = align.max(min),
@@ -171,7 +164,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
             llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
 
             // Declare an internal global `extern_with_linkage_foo` which
-            // is initialized with the address of `foo`.  If `foo` is
+            // is initialized with the address of `foo`. If `foo` is
             // discarded during linking (for example, if `foo` has weak
             // linkage and there are no definitions), then
             // `extern_with_linkage_foo` will instead be initialized to
index d9ccba07a346a1066e93beea9981566f383b15e9..32cd3a4efa227e0b0a5a77a1e0b18a25ef417474 100644 (file)
@@ -191,7 +191,7 @@ pub unsafe fn create_module<'ll>(
         //
         // FIXME(#34960)
         let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or("");
-        let custom_llvm_used = cfg_llvm_root.trim() != "";
+        let custom_llvm_used = !cfg_llvm_root.trim().is_empty();
 
         if !custom_llvm_used && target_data_layout != llvm_data_layout {
             bug!(
index 393bf30e9f83411d5063ba17d76c7657aeb020ee..240a9d2f37184aa8adecf82a837e5d78693e14c5 100644 (file)
@@ -1,6 +1,5 @@
 use crate::common::CodegenCx;
 use crate::coverageinfo;
-use crate::errors::InstrumentCoverageRequiresLLVM12;
 use crate::llvm;
 
 use llvm::coverageinfo::CounterMappingRegion;
@@ -8,7 +7,7 @@
 use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefIdSet;
+use rustc_hir::def_id::DefId;
 use rustc_llvm::RustString;
 use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
@@ -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 }
     }
 
@@ -291,7 +280,7 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
 
     let ignore_unused_generics = tcx.sess.instrument_coverage_except_unused_generics();
 
-    let eligible_def_ids: DefIdSet = tcx
+    let eligible_def_ids: Vec<DefId> = tcx
         .mir_keys(())
         .iter()
         .filter_map(|local_def_id| {
@@ -306,9 +295,8 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
                 DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator
             ) {
                 return None;
-            } else if ignore_unused_generics
-                && tcx.generics_of(def_id).requires_monomorphization(tcx)
-            {
+            }
+            if ignore_unused_generics && tcx.generics_of(def_id).requires_monomorphization(tcx) {
                 return None;
             }
             Some(local_def_id.to_def_id())
@@ -317,7 +305,9 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
 
     let codegenned_def_ids = tcx.codegened_and_inlined_items(());
 
-    for &non_codegenned_def_id in eligible_def_ids.difference(codegenned_def_ids) {
+    for non_codegenned_def_id in
+        eligible_def_ids.into_iter().filter(|id| !codegenned_def_ids.contains(id))
+    {
         let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id);
 
         // If a function is marked `#[no_coverage]`, then skip generating a
index 48e3a812e4f20c839a60a7adcb61969201e82065..f73bbf3d22bd789f17306cfefaff39a7b7885cba 100644 (file)
@@ -782,10 +782,10 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
     codegen_unit_name: &str,
     debug_context: &CodegenUnitDebugContext<'ll, 'tcx>,
 ) -> &'ll DIDescriptor {
-    let mut name_in_debuginfo = match tcx.sess.local_crate_source_file {
-        Some(ref path) => path.clone(),
-        None => PathBuf::from(tcx.crate_name(LOCAL_CRATE).as_str()),
-    };
+    let mut name_in_debuginfo = tcx
+        .sess
+        .local_crate_source_file()
+        .unwrap_or_else(|| PathBuf::from(tcx.crate_name(LOCAL_CRATE).as_str()));
 
     // To avoid breaking split DWARF, we need to ensure that each codegen unit
     // has a unique `DW_AT_name`. This is because there's a remote chance that
@@ -1499,6 +1499,11 @@ pub fn create_vtable_di_node<'ll, 'tcx>(
         return;
     }
 
+    // When full debuginfo is enabled, we want to try and prevent vtables from being
+    // merged. Otherwise debuggers will have a hard time mapping from dyn pointer
+    // to concrete type.
+    llvm::SetUnnamedAddress(vtable, llvm::UnnamedAddr::No);
+
     let vtable_name =
         compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable);
     let vtable_type_di_node = build_vtable_type_di_node(cx, ty, poly_trait_ref);
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 680d810f78eb9b4121e98955f6cbad23629f52a3..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.
@@ -654,7 +654,7 @@ fn codegen_gnu_try<'ll>(
         // Type indicator for the exception being thrown.
         //
         // The first value in this tuple is a pointer to the exception object
-        // being thrown.  The second value is a "selector" indicating which of
+        // being thrown. The second value is a "selector" indicating which of
         // the landing pad clauses the exception's type had been matched to.
         // rust_try ignores the selector.
         bx.switch_to_block(catch);
@@ -718,7 +718,7 @@ fn codegen_emcc_try<'ll>(
         // Type indicator for the exception being thrown.
         //
         // The first value in this tuple is a pointer to the exception object
-        // being thrown.  The second value is a "selector" indicating which of
+        // being thrown. The second value is a "selector" indicating which of
         // the landing pad clauses the exception's type had been matched to.
         bx.switch_to_block(catch);
         let tydesc = bx.eh_catch_typeinfo();
index 182adf81785716fe5abea7b91e0571dc6bda7a8b..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)
             }
         }
@@ -352,10 +351,10 @@ fn scalar_pair_element_llvm_type<'a>(
         let scalar = [a, b][index];
 
         // Make sure to return the same type `immediate_llvm_type` would when
-        // dealing with an immediate pair.  This means that `(bool, bool)` is
+        // dealing with an immediate pair. This means that `(bool, bool)` is
         // effectively represented as `{i8, i8}` in memory and two `i1`s as an
         // immediate, just like `bool` is typically `i8` in memory and only `i1`
-        // when immediate.  We need to load/store `bool` as `i8` to avoid
+        // when immediate. We need to load/store `bool` as `i8` to avoid
         // crippling LLVM optimizations or triggering other LLVM bugs with `i1`.
         if immediate && scalar.is_bool() {
             return cx.type_i1();
index 6eb120157da0205b34c762ec5787d2a9665bd9b0..d3cd085cfb66854f374041ab5d5a2aeba32925bc 100644 (file)
@@ -14,7 +14,7 @@
 
 use std::error::Error;
 use std::fs::File;
-use std::io;
+use std::io::{self, Write};
 use std::path::{Path, PathBuf};
 
 // Re-exporting for rustc_codegen_llvm::back::archive
@@ -116,11 +116,12 @@ pub fn new(
     }
 }
 
-fn try_filter_fat_archs<'a>(
+fn try_filter_fat_archs(
     archs: object::read::Result<&[impl FatArch]>,
     target_arch: object::Architecture,
-    archive_map_data: &'a [u8],
-) -> io::Result<Option<(&'a [u8], u64)>> {
+    archive_path: &Path,
+    archive_map_data: &[u8],
+) -> io::Result<Option<PathBuf>> {
     let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
 
     let desired = match archs.iter().find(|a| a.architecture() == target_arch) {
@@ -128,30 +129,38 @@ fn try_filter_fat_archs<'a>(
         None => return Ok(None),
     };
 
-    Ok(Some((
+    let (mut new_f, extracted_path) = tempfile::Builder::new()
+        .suffix(archive_path.file_name().unwrap())
+        .tempfile()?
+        .keep()
+        .unwrap();
+
+    new_f.write_all(
         desired.data(archive_map_data).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?,
-        desired.offset().into(),
-    )))
+    )?;
+
+    Ok(Some(extracted_path))
 }
 
-pub fn try_extract_macho_fat_archive<'a>(
+pub fn try_extract_macho_fat_archive(
     sess: &Session,
-    archive_bytes: &'a [u8],
-) -> io::Result<Option<(&'a [u8], u64)>> {
+    archive_path: &Path,
+) -> io::Result<Option<PathBuf>> {
+    let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
     let target_arch = match sess.target.arch.as_ref() {
         "aarch64" => object::Architecture::Aarch64,
         "x86_64" => object::Architecture::X86_64,
         _ => return Ok(None),
     };
 
-    match object::macho::FatHeader::parse(archive_bytes) {
+    match object::macho::FatHeader::parse(&*archive_map) {
         Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC => {
-            let archs = object::macho::FatHeader::parse_arch32(archive_bytes);
-            try_filter_fat_archs(archs, target_arch, archive_bytes)
+            let archs = object::macho::FatHeader::parse_arch32(&*archive_map);
+            try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
         }
         Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC_64 => {
-            let archs = object::macho::FatHeader::parse_arch64(archive_bytes);
-            try_filter_fat_archs(archs, target_arch, archive_bytes)
+            let archs = object::macho::FatHeader::parse_arch64(&*archive_map);
+            try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
         }
         // Not a FatHeader at all, just return None.
         _ => Ok(None),
@@ -164,24 +173,21 @@ fn add_archive(
         archive_path: &Path,
         mut skip: Box<dyn FnMut(&str) -> bool + 'static>,
     ) -> io::Result<()> {
-        let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
+        let mut archive_path = archive_path.to_path_buf();
+        if self.sess.target.llvm_target.contains("-apple-macosx") {
+            if let Some(new_archive_path) =
+                try_extract_macho_fat_archive(&self.sess, &archive_path)?
+            {
+                archive_path = new_archive_path
+            }
+        }
+
         if self.src_archives.iter().any(|archive| archive.0 == archive_path) {
             return Ok(());
         }
 
-        let (archive_bytes, offset) = if self.sess.target.llvm_target.contains("-apple-macosx") {
-            if let Some((sub_archive, archive_offset)) =
-                try_extract_macho_fat_archive(&self.sess, &*archive_map)?
-            {
-                (sub_archive, Some(archive_offset))
-            } else {
-                (&*archive_map, None)
-            }
-        } else {
-            (&*archive_map, None)
-        };
-
-        let archive = ArchiveFile::parse(&*archive_bytes)
+        let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
+        let archive = ArchiveFile::parse(&*archive_map)
             .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
         let archive_index = self.src_archives.len();
 
@@ -190,13 +196,9 @@ fn add_archive(
             let file_name = String::from_utf8(entry.name().to_vec())
                 .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
             if !skip(&file_name) {
-                let mut range = entry.file_range();
-                if let Some(offset) = offset {
-                    range.0 += offset;
-                }
                 self.entries.push((
                     file_name.into_bytes(),
-                    ArchiveEntry::FromArchive { archive_index, file_range: range },
+                    ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() },
                 ));
             }
         }
index 342abf81f6a7c0d6b465ce23375dcecd80868297..4ac7bea03ebc01e7a77abcfb8597673e3bf0d3ca 100644 (file)
@@ -445,7 +445,7 @@ fn link_rlib<'a>(
 /// Extract all symbols defined in raw-dylib libraries, collated by library name.
 ///
 /// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library,
-/// then the CodegenResults value contains one NativeLib instance for each block.  However, the
+/// then the CodegenResults value contains one NativeLib instance for each block. However, the
 /// linker appears to expect only a single import library for each library used, so we need to
 /// collate the symbols together by library name before generating the import libraries.
 fn collate_raw_dylibs<'a, 'b>(
@@ -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)]
@@ -1197,7 +1198,7 @@ fn infer_from(
                         if cfg!(any(target_os = "solaris", target_os = "illumos")) {
                             // On historical Solaris systems, "cc" may have
                             // been Sun Studio, which is not flag-compatible
-                            // with "gcc".  This history casts a long shadow,
+                            // with "gcc". This history casts a long shadow,
                             // and many modern illumos distributions today
                             // ship GCC as "gcc" without also making it
                             // available as "cc".
@@ -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 0268659d3b9a13d8515eace64f9d4d2851945bec..eaf1e9817c2038a7934948e9b5fffb50fafa48ce 100644 (file)
@@ -544,7 +544,7 @@ fn gc_sections(&mut self, keep_metadata: bool) {
         // link times negatively.
         //
         // -dead_strip can't be part of the pre_link_args because it's also used
-        // for partial linking when using multiple codegen units (-r).  So we
+        // for partial linking when using multiple codegen units (-r). So we
         // insert it here.
         if self.sess.target.is_like_osx {
             self.linker_arg("-dead_strip");
index 8cb7d74b90d4b40dc6393cd63b5925b7a3260c9c..57a99e74c21ade04464f985e4623fa635e1fdddf 100644 (file)
@@ -173,11 +173,15 @@ fn exported_symbols_provider_local(
         return &[];
     }
 
-    let mut symbols: Vec<_> = tcx
-        .reachable_non_generics(LOCAL_CRATE)
-        .iter()
-        .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info))
-        .collect();
+    // FIXME: Sorting this is unnecessary since we are sorting later anyway.
+    //        Can we skip the later sorting?
+    let mut symbols: Vec<_> = tcx.with_stable_hashing_context(|hcx| {
+        tcx.reachable_non_generics(LOCAL_CRATE)
+            .to_sorted(&hcx, true)
+            .into_iter()
+            .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info))
+            .collect()
+    });
 
     if tcx.entry_fn(()).is_some() {
         let exported_symbol =
index 25dc88c535da9c69c110a27dbf2143e7c7af3f56..9f1614af7b16c9a232546c56ab9f5d5016c22472 100644 (file)
@@ -105,7 +105,7 @@ pub struct ModuleConfig {
     pub emit_thin_lto: bool,
     pub bc_cmdline: String,
 
-    // Miscellaneous flags.  These are mostly copied from command-line
+    // Miscellaneous flags. These are mostly copied from command-line
     // options.
     pub verify_llvm_ir: bool,
     pub no_prepopulate_passes: bool,
@@ -538,7 +538,7 @@ fn produce_final_output_artifacts(
 
     let copy_if_one_unit = |output_type: OutputType, keep_numbered: bool| {
         if compiled_modules.modules.len() == 1 {
-            // 1) Only one codegen unit.  In this case it's no difficulty
+            // 1) Only one codegen unit. In this case it's no difficulty
             //    to copy `foo.0.x` to `foo.x`.
             let module_name = Some(&compiled_modules.modules[0].name[..]);
             let path = crate_output.temp_path(output_type, module_name);
@@ -557,15 +557,15 @@ fn produce_final_output_artifacts(
                 .to_owned();
 
             if crate_output.outputs.contains_key(&output_type) {
-                // 2) Multiple codegen units, with `--emit foo=some_name`.  We have
+                // 2) Multiple codegen units, with `--emit foo=some_name`. We have
                 //    no good solution for this case, so warn the user.
                 sess.emit_warning(errors::IgnoringEmitPath { extension });
             } else if crate_output.single_output_file.is_some() {
-                // 3) Multiple codegen units, with `-o some_name`.  We have
+                // 3) Multiple codegen units, with `-o some_name`. We have
                 //    no good solution for this case, so warn the user.
                 sess.emit_warning(errors::IgnoringOutput { extension });
             } else {
-                // 4) Multiple codegen units, but no explicit name.  We
+                // 4) Multiple codegen units, but no explicit name. We
                 //    just leave the `foo.0.x` files in place.
                 // (We don't have to do any work in this case.)
             }
@@ -579,7 +579,7 @@ fn produce_final_output_artifacts(
         match *output_type {
             OutputType::Bitcode => {
                 user_wants_bitcode = true;
-                // Copy to .bc, but always keep the .0.bc.  There is a later
+                // Copy to .bc, but always keep the .0.bc. There is a later
                 // check to figure out if we should delete .0.bc files, or keep
                 // them for making an rlib.
                 copy_if_one_unit(OutputType::Bitcode, true);
@@ -611,7 +611,7 @@ fn produce_final_output_artifacts(
     // `-C save-temps` or `--emit=` flags).
 
     if !sess.opts.cg.save_temps {
-        // Remove the temporary .#module-name#.o objects.  If the user didn't
+        // Remove the temporary .#module-name#.o objects. If the user didn't
         // explicitly request bitcode (with --emit=bc), and the bitcode is not
         // needed for building an rlib, then we must remove .#module-name#.bc as
         // well.
index f7312f6fcdafdc6d0d90539fa70042a9fbd7f7c8..02b502d948c2c890b83430bb45ee9a5791646a49 100644 (file)
@@ -436,7 +436,7 @@ fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             cx.type_func(&[], cx.type_int())
         };
 
-        let main_ret_ty = cx.tcx().fn_sig(rust_main_def_id).output();
+        let main_ret_ty = cx.tcx().fn_sig(rust_main_def_id).no_bound_vars().unwrap().output();
         // Given that `main()` has no arguments,
         // then its return type cannot have
         // late-bound regions, since late-bound
@@ -964,16 +964,19 @@ pub fn provide(providers: &mut Providers) {
         };
 
         let (defids, _) = tcx.collect_and_partition_mono_items(cratenum);
-        for id in &*defids {
+
+        let any_for_speed = defids.items().any(|id| {
             let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id);
             match optimize {
-                attr::OptimizeAttr::None => continue,
-                attr::OptimizeAttr::Size => continue,
-                attr::OptimizeAttr::Speed => {
-                    return for_speed;
-                }
+                attr::OptimizeAttr::None | attr::OptimizeAttr::Size => false,
+                attr::OptimizeAttr::Speed => true,
             }
+        });
+
+        if any_for_speed {
+            return for_speed;
         }
+
         tcx.sess.opts.optimize
     };
 }
index b0fa7745667360d642a4fbd8c89ea0a71c6ef8d5..87b819ebc9849504a6be8219bcfa67bda680c416 100644 (file)
@@ -214,7 +214,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
             }
         } else if attr.has_name(sym::cmse_nonsecure_entry) {
             if validate_fn_only_attr(attr.span)
-                && !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. })
+                && !matches!(tcx.fn_sig(did).skip_binder().abi(), abi::Abi::C { .. })
             {
                 struct_span_err!(
                     tcx.sess,
@@ -234,7 +234,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
         } else if attr.has_name(sym::track_caller) {
             if !tcx.is_closure(did.to_def_id())
                 && validate_fn_only_attr(attr.span)
-                && tcx.fn_sig(did).abi() != abi::Abi::Rust
+                && tcx.fn_sig(did).skip_binder().abi() != abi::Abi::Rust
             {
                 struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
                     .emit();
@@ -266,7 +266,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
             }
         } else if attr.has_name(sym::target_feature) {
             if !tcx.is_closure(did.to_def_id())
-                && tcx.fn_sig(did).unsafety() == hir::Unsafety::Normal
+                && tcx.fn_sig(did).skip_binder().unsafety() == hir::Unsafety::Normal
             {
                 if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
                     // The `#[target_feature]` attribute is allowed on
@@ -658,13 +658,13 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
         sole_meta_list
     {
         // According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header,
-        // the ordinal must fit into 16 bits.  Similarly, the Ordinal field in COFFShortExport (defined
+        // the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
         // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information
         // to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
         //
         // FIXME: should we allow an ordinal of 0?  The MSVC toolchain has inconsistent support for this:
         // both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies
-        // a zero ordinal.  However, llvm-dlltool is perfectly happy to generate an import library
+        // a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library
         // for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import
         // library produced by LLVM with an ordinal of 0, and it generates an .EXE.  (I don't know yet
         // if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment
index 1599ccbb2594c747e7ef31495e0c2171f5c06417..b0e007ce0097bd4c966edc23d1ce16017a0885c6 100644 (file)
@@ -414,6 +414,7 @@ fn push_debuginfo_type_name<'tcx>(
         | ty::Placeholder(..)
         | ty::Alias(..)
         | ty::Bound(..)
+        | ty::GeneratorWitnessMIR(..)
         | ty::GeneratorWitness(..) => {
             bug!(
                 "debuginfo: Trying to create type name for \
index dd1ac2c74aed4fe2d628ffc17958f407a3a0a461..95aad10fdb0f9852505cd08ebffa88f6f62ac7c2 100644 (file)
@@ -36,7 +36,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     // Arguments get assigned to by means of the function being called
     for arg in mir.args_iter() {
-        analyzer.assign(arg, mir::START_BLOCK.start_location());
+        analyzer.assign(arg, DefLocation::Argument);
     }
 
     // If there exists a local definition that dominates all uses of that local,
@@ -64,7 +64,22 @@ enum LocalKind {
     /// A scalar or a scalar pair local that is neither defined nor used.
     Unused,
     /// A scalar or a scalar pair local with a single definition that dominates all uses.
-    SSA(mir::Location),
+    SSA(DefLocation),
+}
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+enum DefLocation {
+    Argument,
+    Body(Location),
+}
+
+impl DefLocation {
+    fn dominates(self, location: Location, dominators: &Dominators<mir::BasicBlock>) -> bool {
+        match self {
+            DefLocation::Argument => true,
+            DefLocation::Body(def) => def.successor_within_block().dominates(location, dominators),
+        }
+    }
 }
 
 struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
@@ -74,17 +89,13 @@ struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
 }
 
 impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
-    fn assign(&mut self, local: mir::Local, location: Location) {
+    fn assign(&mut self, local: mir::Local, location: DefLocation) {
         let kind = &mut self.locals[local];
         match *kind {
             LocalKind::ZST => {}
             LocalKind::Memory => {}
-            LocalKind::Unused => {
-                *kind = LocalKind::SSA(location);
-            }
-            LocalKind::SSA(_) => {
-                *kind = LocalKind::Memory;
-            }
+            LocalKind::Unused => *kind = LocalKind::SSA(location),
+            LocalKind::SSA(_) => *kind = LocalKind::Memory,
         }
     }
 
@@ -166,7 +177,7 @@ fn visit_assign(
         debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);
 
         if let Some(local) = place.as_local() {
-            self.assign(local, location);
+            self.assign(local, DefLocation::Body(location));
             if self.locals[local] != LocalKind::Memory {
                 let decl_span = self.fx.mir.local_decls[local].source_info.span;
                 if !self.fx.rvalue_creates_operand(rvalue, decl_span) {
@@ -189,7 +200,7 @@ fn visit_local(&mut self, local: mir::Local, context: PlaceContext, location: Lo
         match context {
             PlaceContext::MutatingUse(MutatingUseContext::Call)
             | PlaceContext::MutatingUse(MutatingUseContext::Yield) => {
-                self.assign(local, location);
+                self.assign(local, DefLocation::Body(location));
             }
 
             PlaceContext::NonUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}
index 978aff511bfa74d07f2ecbcc4a20aa3155d2e62d..2623a650e07b28f4c86e30263a192c90a7ec0814 100644 (file)
@@ -39,7 +39,6 @@ enum MergingSucc {
 struct TerminatorCodegenHelper<'tcx> {
     bb: mir::BasicBlock,
     terminator: &'tcx mir::Terminator<'tcx>,
-    funclet_bb: Option<mir::BasicBlock>,
 }
 
 impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
@@ -49,28 +48,24 @@ fn funclet<'b, Bx: BuilderMethods<'a, 'tcx>>(
         &self,
         fx: &'b mut FunctionCx<'a, 'tcx, Bx>,
     ) -> Option<&'b Bx::Funclet> {
-        let funclet_bb = self.funclet_bb?;
-        if base::wants_msvc_seh(fx.cx.tcx().sess) {
-            // If `landing_pad_for` hasn't been called yet to create the `Funclet`,
-            // it has to be now. This may not seem necessary, as RPO should lead
-            // to all the unwind edges being visited (and so to `landing_pad_for`
-            // getting called for them), before building any of the blocks inside
-            // the funclet itself - however, if MIR contains edges that end up not
-            // being needed in the LLVM IR after monomorphization, the funclet may
-            // be unreachable, and we don't have yet a way to skip building it in
-            // such an eventuality (which may be a better solution than this).
-            if fx.funclets[funclet_bb].is_none() {
-                fx.landing_pad_for(funclet_bb);
-            }
-
-            Some(
-                fx.funclets[funclet_bb]
-                    .as_ref()
-                    .expect("landing_pad_for didn't also create funclets entry"),
-            )
-        } else {
-            None
+        let cleanup_kinds = (&fx.cleanup_kinds).as_ref()?;
+        let funclet_bb = cleanup_kinds[self.bb].funclet_bb(self.bb)?;
+        // If `landing_pad_for` hasn't been called yet to create the `Funclet`,
+        // it has to be now. This may not seem necessary, as RPO should lead
+        // to all the unwind edges being visited (and so to `landing_pad_for`
+        // getting called for them), before building any of the blocks inside
+        // the funclet itself - however, if MIR contains edges that end up not
+        // being needed in the LLVM IR after monomorphization, the funclet may
+        // be unreachable, and we don't have yet a way to skip building it in
+        // such an eventuality (which may be a better solution than this).
+        if fx.funclets[funclet_bb].is_none() {
+            fx.landing_pad_for(funclet_bb);
         }
+        Some(
+            fx.funclets[funclet_bb]
+                .as_ref()
+                .expect("landing_pad_for didn't also create funclets entry"),
+        )
     }
 
     /// Get a basic block (creating it if necessary), possibly with cleanup
@@ -104,23 +99,24 @@ fn llbb_characteristics<Bx: BuilderMethods<'a, 'tcx>>(
         fx: &mut FunctionCx<'a, 'tcx, Bx>,
         target: mir::BasicBlock,
     ) -> (bool, bool) {
-        let target_funclet = fx.cleanup_kinds[target].funclet_bb(target);
-        let (needs_landing_pad, is_cleanupret) = match (self.funclet_bb, target_funclet) {
-            (None, None) => (false, false),
-            (None, Some(_)) => (true, false),
-            (Some(_), None) => {
-                let span = self.terminator.source_info.span;
-                span_bug!(span, "{:?} - jump out of cleanup?", self.terminator);
-            }
-            (Some(f), Some(t_f)) => {
-                if f == t_f || !base::wants_msvc_seh(fx.cx.tcx().sess) {
-                    (false, false)
-                } else {
-                    (true, true)
+        if let Some(ref cleanup_kinds) = fx.cleanup_kinds {
+            let funclet_bb = cleanup_kinds[self.bb].funclet_bb(self.bb);
+            let target_funclet = cleanup_kinds[target].funclet_bb(target);
+            let (needs_landing_pad, is_cleanupret) = match (funclet_bb, target_funclet) {
+                (None, None) => (false, false),
+                (None, Some(_)) => (true, false),
+                (Some(f), Some(t_f)) => (f != t_f, f != t_f),
+                (Some(_), None) => {
+                    let span = self.terminator.source_info.span;
+                    span_bug!(span, "{:?} - jump out of cleanup?", self.terminator);
                 }
-            }
-        };
-        (needs_landing_pad, is_cleanupret)
+            };
+            (needs_landing_pad, is_cleanupret)
+        } else {
+            let needs_landing_pad = !fx.mir[self.bb].is_cleanup && fx.mir[target].is_cleanup;
+            let is_cleanupret = false;
+            (needs_landing_pad, is_cleanupret)
+        }
     }
 
     fn funclet_br<Bx: BuilderMethods<'a, 'tcx>>(
@@ -678,8 +674,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!({
@@ -1253,9 +1249,7 @@ fn codegen_terminator(
     ) -> MergingSucc {
         debug!("codegen_terminator: {:?}", terminator);
 
-        // Create the cleanup bundle, if needed.
-        let funclet_bb = self.cleanup_kinds[bb].funclet_bb(bb);
-        let helper = TerminatorCodegenHelper { bb, terminator, funclet_bb };
+        let helper = TerminatorCodegenHelper { bb, terminator };
 
         let mergeable_succ = || {
             // Note: any call to `switch_to_block` will invalidate a `true` value
@@ -1801,8 +1795,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 b7982b633f57fa8b38b93983d078358152820d68..e9bc40c33107706b6167373a5ace60f8b8ac6a2b 100644 (file)
@@ -57,9 +57,9 @@ pub struct DebugScope<S, L> {
 }
 
 impl<'tcx, S: Copy, L: Copy> DebugScope<S, L> {
-    /// DILocations inherit source file name from the parent DIScope.  Due to macro expansions
+    /// DILocations inherit source file name from the parent DIScope. Due to macro expansions
     /// it may so happen that the current span belongs to a different file than the DIScope
-    /// corresponding to span's containing source scope.  If so, we need to create a DIScope
+    /// corresponding to span's containing source scope. If so, we need to create a DIScope
     /// "extension" into that file.
     pub fn adjust_dbg_scope_for_span<Cx: CodegenMethods<'tcx, DIScope = S, DILocation = L>>(
         &self,
index 79c66a955e76d856cb534aef6a6da2a6ff9cf107..bb265b8289ed977364b8126ffbba2459eec18f2d 100644 (file)
@@ -1,3 +1,4 @@
+use crate::base;
 use crate::traits::*;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
@@ -58,7 +59,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
     cached_llbbs: IndexVec<mir::BasicBlock, CachedLlbb<Bx::BasicBlock>>,
 
     /// The funclet status of each basic block
-    cleanup_kinds: IndexVec<mir::BasicBlock, analyze::CleanupKind>,
+    cleanup_kinds: Option<IndexVec<mir::BasicBlock, analyze::CleanupKind>>,
 
     /// When targeting MSVC, this stores the cleanup info for each funclet BB.
     /// This is initialized at the same time as the `landing_pads` entry for the
@@ -166,7 +167,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         start_bx.set_personality_fn(cx.eh_personality());
     }
 
-    let cleanup_kinds = analyze::cleanup_kinds(&mir);
+    let cleanup_kinds =
+        if base::wants_msvc_seh(cx.tcx().sess) { Some(analyze::cleanup_kinds(&mir)) } else { None };
+
     let cached_llbbs: IndexVec<mir::BasicBlock, CachedLlbb<Bx::BasicBlock>> =
         mir.basic_blocks
             .indices()
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 19452c8cdc805da6068a7b37f8a871368961588b..60fbceb344d88dd360120d8d2594375b74793c60 100644 (file)
@@ -91,6 +91,7 @@ pub fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx
             mir::StatementKind::FakeRead(..)
             | mir::StatementKind::Retag { .. }
             | mir::StatementKind::AscribeUserType(..)
+            | mir::StatementKind::ConstEvalCounter
             | mir::StatementKind::Nop => {}
         }
     }
index 13472cc2bfa0a5c4b8ed7ba81baa6eb3114ac9f9..0579f7815352772807a19789d6928440256383b2 100644 (file)
@@ -36,16 +36,16 @@ fn into(self) -> InterpErrorInfo<'tcx> {
 impl fmt::Display for ConstEvalErrKind {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use self::ConstEvalErrKind::*;
-        match *self {
+        match self {
             ConstAccessesStatic => write!(f, "constant accesses static"),
             ModifiedGlobal => {
                 write!(f, "modifying a static's initial value from another static's initializer")
             }
-            AssertFailure(ref msg) => write!(f, "{:?}", msg),
+            AssertFailure(msg) => write!(f, "{:?}", msg),
             Panic { msg, line, col, file } => {
                 write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col)
             }
-            Abort(ref msg) => write!(f, "{}", msg),
+            Abort(msg) => write!(f, "{}", msg),
         }
     }
 }
index 351c701305adc022b1c24dcf59ecf2e4ff2c8764..f92277b111374ea268d5492dc76fd4d44b91872e 100644 (file)
@@ -66,7 +66,7 @@ fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
                 if cfg!(debug_assertions) && stab.promotable {
                     let sig = tcx.fn_sig(def_id);
                     assert_eq!(
-                        sig.unsafety(),
+                        sig.skip_binder().unsafety(),
                         hir::Unsafety::Normal,
                         "don't mark const unsafe fns as promotable",
                         // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
index e006a62feeabd12bc568da7c5c42e76bdde1cc2f..a5bc121485d8cde6a3beb7dd0b1a601b32e1c445 100644 (file)
@@ -225,7 +225,7 @@ fn hook_special_const_fn(
     /// `align_offset(ptr, target_align)` needs special handling in const eval, because the pointer
     /// may not have an address.
     ///
-    /// If `ptr` does have a known address, then we return `CONTINUE` and the function call should
+    /// If `ptr` does have a known address, then we return `Continue(())` and the function call should
     /// proceed as normal.
     ///
     /// If `ptr` doesn't have an address, but its underlying allocation's alignment is at most
@@ -273,18 +273,18 @@ fn align_offset(
                         ret,
                         StackPopUnwind::NotAllowed,
                     )?;
-                    Ok(ControlFlow::BREAK)
+                    Ok(ControlFlow::Break(()))
                 } else {
                     // Not alignable in const, return `usize::MAX`.
                     let usize_max = Scalar::from_machine_usize(self.machine_usize_max(), self);
                     self.write_scalar(usize_max, dest)?;
                     self.return_to_block(ret)?;
-                    Ok(ControlFlow::BREAK)
+                    Ok(ControlFlow::Break(()))
                 }
             }
             Err(_addr) => {
                 // The pointer has an address, continue with function call.
-                Ok(ControlFlow::CONTINUE)
+                Ok(ControlFlow::Continue(()))
             }
         }
     }
@@ -408,7 +408,7 @@ fn find_mir_or_eval_fn(
         // Only check non-glue functions
         if let ty::InstanceDef::Item(def) = instance.def {
             // Execution might have wandered off into other crates, so we cannot do a stability-
-            // sensitive check here.  But we can at least rule out functions that are not const
+            // sensitive check here. But we can at least rule out functions that are not const
             // at all.
             if !ecx.tcx.is_const_fn_raw(def.did) {
                 // allow calling functions inside a trait marked with #[const_trait].
@@ -533,7 +533,7 @@ fn assert_panic(
         let eval_to_int =
             |op| ecx.read_immediate(&ecx.eval_operand(op, None)?).map(|x| x.to_const_int());
         let err = match msg {
-            BoundsCheck { ref len, ref index } => {
+            BoundsCheck { len, index } => {
                 let len = eval_to_int(len)?;
                 let index = eval_to_int(index)?;
                 BoundsCheck { len, index }
@@ -561,8 +561,8 @@ fn binary_ptr_op(
         throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time");
     }
 
-    fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
-        // The step limit has already been hit in a previous call to `before_terminator`.
+    fn increment_const_eval_counter(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
+        // The step limit has already been hit in a previous call to `increment_const_eval_counter`.
         if ecx.machine.steps_remaining == 0 {
             return Ok(());
         }
index 498c008738793912e46e0b25afca0b8180a07d34..c52886b77e64bc77388757aa9c520a6b96ea43e4 100644 (file)
@@ -151,7 +151,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
         // FIXME(oli-obk): we can probably encode closures just like structs
         | ty::Closure(..)
         | ty::Generator(..)
-        | ty::GeneratorWitness(..) => Err(ValTreeCreationError::NonSupportedType),
+        | ty::GeneratorWitness(..) |ty::GeneratorWitnessMIR(..)=> Err(ValTreeCreationError::NonSupportedType),
     }
 }
 
@@ -314,6 +314,7 @@ pub fn valtree_to_const_value<'tcx>(
         | ty::Closure(..)
         | ty::Generator(..)
         | ty::GeneratorWitness(..)
+        | ty::GeneratorWitnessMIR(..)
         | ty::FnPtr(_)
         | ty::RawPtr(_)
         | ty::Str
index 986b6d655300168046dad275e318667b1adff014..b2c847d3fd8dd6fca2403ecd5d9216ae4c5e63f4 100644 (file)
@@ -347,7 +347,7 @@ fn unsize_into_ptr(
                 let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
                 self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
             }
-            (_, &ty::Dynamic(ref data, _, ty::Dyn)) => {
+            (_, &ty::Dynamic(data, _, ty::Dyn)) => {
                 // Initial cast from sized to dyn trait
                 let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?;
                 let ptr = self.read_scalar(src)?;
index f551b5c29114d9984fcf108ceb1b9e12628db580..d13fed7a9c2631fa366200f8686433831c9d558b 100644 (file)
@@ -196,7 +196,7 @@ pub fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> {
         }
     }
 
-    /// Overwrite the local.  If the local can be overwritten in place, return a reference
+    /// Overwrite the local. If the local can be overwritten in place, return a reference
     /// to do so; otherwise return the `MemPlace` to consult instead.
     ///
     /// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from
@@ -592,7 +592,7 @@ pub(super) fn size_and_align_of(
                 );
 
                 // Recurse to get the size of the dynamically sized field (must be
-                // the last field).  Can't have foreign types here, how would we
+                // the last field). Can't have foreign types here, how would we
                 // adjust alignment and size for them?
                 let field = layout.field(self, layout.fields.count() - 1);
                 let Some((unsized_size, mut unsized_align)) = self.size_and_align_of(metadata, &field)? else {
index 458cc6180d53e47281bf97a9754125159963cb96..54528b1dbf4a0e252fe90929b9c1945ae43ca3a5 100644 (file)
@@ -59,7 +59,7 @@ struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_ev
 
 #[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
 enum InternMode {
-    /// A static and its current mutability.  Below shared references inside a `static mut`,
+    /// A static and its current mutability. Below shared references inside a `static mut`,
     /// this is *immutable*, and below mutable references inside an `UnsafeCell`, this
     /// is *mutable*.
     Static(hir::Mutability),
@@ -296,7 +296,7 @@ fn visit_value(&mut self, mplace: &MPlaceTy<'tcx>) -> InterpResult<'tcx> {
                         }
                     }
                     InternMode::Const => {
-                        // Ignore `UnsafeCell`, everything is immutable.  Validity does some sanity
+                        // Ignore `UnsafeCell`, everything is immutable. Validity does some sanity
                         // checking for mutable references that we encounter -- they must all be
                         // ZST.
                         InternMode::Const
@@ -330,7 +330,7 @@ pub enum InternKind {
 
 /// Intern `ret` and everything it references.
 ///
-/// This *cannot raise an interpreter error*.  Doing so is left to validation, which
+/// This *cannot raise an interpreter error*. Doing so is left to validation, which
 /// tracks where in the value we are and thus can show much better error messages.
 #[instrument(level = "debug", skip(ecx))]
 pub fn intern_const_alloc_recursive<
@@ -379,7 +379,7 @@ pub fn intern_const_alloc_recursive<
             inside_unsafe_cell: false,
         }
         .visit_value(&mplace);
-        // We deliberately *ignore* interpreter errors here.  When there is a problem, the remaining
+        // We deliberately *ignore* interpreter errors here. When there is a problem, the remaining
         // references are "leftover"-interned, and later validation will show a proper error
         // and point at the right part of the value causing the problem.
         match res {
@@ -454,7 +454,7 @@ pub fn intern_const_alloc_recursive<
             return Err(reported);
         } else if ecx.tcx.try_get_global_alloc(alloc_id).is_none() {
             // We have hit an `AllocId` that is neither in local or global memory and isn't
-            // marked as dangling by local memory.  That should be impossible.
+            // marked as dangling by local memory. That should be impossible.
             span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id);
         }
     }
index 666fcbd6f80488cc2dff1abc141252a50b72aafc..907f014dfb5180f90b48e2a2403c9d6b38dd699e 100644 (file)
@@ -79,9 +79,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
         }
         sym::variant_count => match tp_ty.kind() {
             // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
-            ty::Adt(ref adt, _) => {
-                ConstValue::from_machine_usize(adt.variants().len() as u64, &tcx)
-            }
+            ty::Adt(adt, _) => ConstValue::from_machine_usize(adt.variants().len() as u64, &tcx),
             ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
                 throw_inval!(TooGeneric)
             }
@@ -103,6 +101,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
             | ty::Closure(_, _)
             | ty::Generator(_, _, _)
             | ty::GeneratorWitness(_)
+            | ty::GeneratorWitnessMIR(_, _)
             | ty::Never
             | ty::Tuple(_)
             | ty::Error(_) => ConstValue::from_machine_usize(0u64, &tcx),
@@ -449,7 +448,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(
@@ -463,7 +462,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 1d4ef20d0651f7bd11d7cb466f0290d375ff27d8..76ed7b80f8d81b7a69c553a2597450cd5710572a 100644 (file)
@@ -180,7 +180,7 @@ fn find_mir_or_eval_fn(
         unwind: StackPopUnwind,
     ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>;
 
-    /// Execute `fn_val`.  It is the hook's responsibility to advance the instruction
+    /// Execute `fn_val`. It is the hook's responsibility to advance the instruction
     /// pointer as appropriate.
     fn call_extra_fn(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
@@ -244,12 +244,18 @@ fn access_local_mut<'a>(
     }
 
     /// Called before a basic block terminator is executed.
-    /// You can use this to detect endlessly running programs.
     #[inline]
     fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
         Ok(())
     }
 
+    /// Called when the interpreter encounters a `StatementKind::ConstEvalCounter` instruction.
+    /// You can use this to detect long or endlessly running programs.
+    #[inline]
+    fn increment_const_eval_counter(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
+        Ok(())
+    }
+
     /// Called before a global allocation is accessed.
     /// `def_id` is `Some` if this is the "lazy" allocation of a static.
     #[inline]
@@ -439,7 +445,7 @@ fn after_stack_pop(
 }
 
 /// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines
-/// (CTFE and ConstProp) use the same instance.  Here, we share that code.
+/// (CTFE and ConstProp) use the same instance. Here, we share that code.
 pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     type Provenance = AllocId;
     type ProvenanceExtra = ();
index 5b1ac6b2f65e29f7bc7a726d3044a6fd5cb95654..291bfb2b55896dd73412d453533eab6223c56a6f 100644 (file)
@@ -146,7 +146,7 @@ pub fn alloc_map(&self) -> &M::MemoryMap {
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Call this to turn untagged "global" pointers (obtained via `tcx`) into
-    /// the machine pointer to the allocation.  Must never be used
+    /// the machine pointer to the allocation. Must never be used
     /// for any other pointers, nor for TLS statics.
     ///
     /// Using the resulting pointer represents a *direct* access to that memory
@@ -536,7 +536,7 @@ fn get_alloc_raw(
         &self,
         id: AllocId,
     ) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra>> {
-        // The error type of the inner closure here is somewhat funny.  We have two
+        // The error type of the inner closure here is somewhat funny. We have two
         // ways of "erroring": An actual error, or because we got a reference from
         // `get_global_alloc` that we can actually use directly without inserting anything anywhere.
         // So the error type is `InterpResult<'tcx, &Allocation<M::Provenance>>`.
@@ -863,7 +863,7 @@ fn write_allocation_track_relocs<'tcx, Prov: Provenance, Extra>(
 
             write!(fmt, "{id:?}")?;
             match self.ecx.memory.alloc_map.get(id) {
-                Some(&(kind, ref alloc)) => {
+                Some((kind, alloc)) => {
                     // normal alloc
                     write!(fmt, " ({}, ", kind)?;
                     write_allocation_track_relocs(
index fcc6f8ea85282673c6f790d08ab13af0a85520f0..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 })
             }
@@ -488,7 +488,7 @@ pub fn place_to_op(
         Ok(OpTy { op, layout: place.layout, align: Some(place.align) })
     }
 
-    /// Evaluate a place with the goal of reading from it.  This lets us sometimes
+    /// Evaluate a place with the goal of reading from it. This lets us sometimes
     /// avoid allocations.
     pub fn eval_place_to_op(
         &self,
@@ -533,11 +533,11 @@ pub fn eval_operand(
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         use rustc_middle::mir::Operand::*;
-        let op = match *mir_op {
+        let op = match mir_op {
             // FIXME: do some more logic on `move` to invalidate the old location
-            Copy(place) | Move(place) => self.eval_place_to_op(place, layout)?,
+            &Copy(place) | &Move(place) => self.eval_place_to_op(place, layout)?,
 
-            Constant(ref constant) => {
+            Constant(constant) => {
                 let c =
                     self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?;
 
index 97a73e98abcbca9d563027620fc8a74630014606..274af61ee7c1d5899b1d2d8b3a2700c912d9a0fa 100644 (file)
@@ -233,7 +233,7 @@ pub(crate) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
                 _ => bug!("len not supported on unsized type {:?}", self.layout.ty),
             }
         } else {
-            // Go through the layout.  There are lots of types that support a length,
+            // Go through the layout. There are lots of types that support a length,
             // e.g., SIMD types. (But not all repr(simd) types even have FieldsShape::Array!)
             match self.layout.fields {
                 abi::FieldsShape::Array { count, .. } => Ok(count),
@@ -294,7 +294,7 @@ impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M>
     M: Machine<'mir, 'tcx, Provenance = Prov>,
 {
     /// Take a value, which represents a (thin or wide) reference, and make it a place.
-    /// Alignment is just based on the type.  This is the inverse of `MemPlace::to_ref()`.
+    /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`.
     ///
     /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not
     /// want to ever use the place for memory access!
@@ -703,7 +703,7 @@ pub fn force_allocation(
                     &mut Operand::Immediate(local_val) => {
                         // We need to make an allocation.
 
-                        // We need the layout of the local.  We can NOT use the layout we got,
+                        // We need the layout of the local. We can NOT use the layout we got,
                         // that might e.g., be an inner field of a struct with `Scalar` layout,
                         // that has different alignment than the outer field.
                         let local_layout =
index 81b44a49484d0a72e213d8a32b510e784b7938b1..d101937fd7406cc64f214f60b0c1073024b87bc3 100644 (file)
@@ -111,7 +111,7 @@ pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
                 M::retag_place_contents(self, *kind, &dest)?;
             }
 
-            Intrinsic(box ref intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
+            Intrinsic(box intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
 
             // Statements we do not track.
             AscribeUserType(..) => {}
@@ -129,6 +129,10 @@ pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
             // FIXME(#73156): Handle source code coverage in const eval
             Coverage(..) => {}
 
+            ConstEvalCounter => {
+                M::increment_const_eval_counter(self)?;
+            }
+
             // Defined to do nothing. These are added by optimization passes, to avoid changing the
             // size of MIR constantly.
             Nop => {}
@@ -163,8 +167,8 @@ pub fn eval_rvalue_into_place(
                 self.copy_op(&op, &dest, /*allow_transmute*/ false)?;
             }
 
-            CopyForDeref(ref place) => {
-                let op = self.eval_place_to_op(*place, Some(dest.layout))?;
+            CopyForDeref(place) => {
+                let op = self.eval_place_to_op(place, Some(dest.layout))?;
                 self.copy_op(&op, &dest, /* allow_transmute*/ false)?;
             }
 
index 550c7a44c4199e6cf7043d4dd60f6e49c7f4b436..da320cd1cd5f0c6444b1ce8a8d56fffe2e776c78 100644 (file)
@@ -446,7 +446,7 @@ pub(crate) fn eval_fn_call(
                     // they go to.
 
                     // For where they come from: If the ABI is RustCall, we untuple the
-                    // last incoming argument.  These two iterators do not have the same type,
+                    // last incoming argument. These two iterators do not have the same type,
                     // so to keep the code paths uniform we accept an allocation
                     // (for RustCall ABI only).
                     let caller_args: Cow<'_, [OpTy<'tcx, M::Provenance>]> =
@@ -481,7 +481,7 @@ pub(crate) fn eval_fn_call(
                         .filter(|arg_and_abi| !matches!(arg_and_abi.1.mode, PassMode::Ignore));
 
                     // Now we have to spread them out across the callee's locals,
-                    // taking into account the `spread_arg`.  If we could write
+                    // taking into account the `spread_arg`. If we could write
                     // this is a single iterator (that handles `spread_arg`), then
                     // `pass_argument` would be the loop body. It takes care to
                     // not advance `caller_iter` for ZSTs.
@@ -648,8 +648,8 @@ fn drop_in_place(
         unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx> {
         trace!("drop_in_place: {:?},\n  {:?}, {:?}", *place, place.layout.ty, instance);
-        // We take the address of the object.  This may well be unaligned, which is fine
-        // for us here.  However, unaligned accesses will probably make the actual drop
+        // We take the address of the object. This may well be unaligned, which is fine
+        // for us here. However, unaligned accesses will probably make the actual drop
         // implementation fail -- a problem shared by rustc.
         let place = self.force_allocation(place)?;
 
index a61d3ab40a5ca1c0efa4c9d1339ef95bf38be99b..cabc65e2c077e674d356938d939341dbb8bafb54 100644 (file)
@@ -26,7 +26,7 @@ impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
 
         fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             if !ty.needs_subst() {
-                return ControlFlow::CONTINUE;
+                return ControlFlow::Continue(());
             }
 
             match *ty.kind() {
@@ -48,7 +48,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                             return subst.visit_with(self);
                         }
                     }
-                    ControlFlow::CONTINUE
+                    ControlFlow::Continue(())
                 }
                 _ => ty.super_visit_with(self),
             }
index f905d3fb479a0b7e343c7dd187239f94f3543705..aa539516d5e503ee328cb9734b7b55ff034c4d74 100644 (file)
@@ -175,7 +175,7 @@ fn write_path(out: &mut String, path: &[PathElem]) {
             TupleElem(idx) => write!(out, ".{}", idx),
             ArrayElem(idx) => write!(out, "[{}]", idx),
             // `.<deref>` does not match Rust syntax, but it is more readable for long paths -- and
-            // some of the other items here also are not Rust syntax.  Actually we can't
+            // some of the other items here also are not Rust syntax. Actually we can't
             // even use the usual syntax because we are just showing the projections,
             // not the root.
             Deref => write!(out, ".<deref>"),
@@ -419,7 +419,7 @@ fn check_safe_pointer(
             )
         }
         // Recursive checking
-        if let Some(ref mut ref_tracking) = self.ref_tracking {
+        if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() {
             // Proceed recursively even for ZST, no reason to skip them!
             // `!` is a ZST and we want to validate it.
             if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
@@ -484,7 +484,7 @@ fn check_safe_pointer(
     }
 
     /// Check if this is a value of primitive type, and if yes check the validity of the value
-    /// at that type.  Return `true` if the type is indeed primitive.
+    /// at that type. Return `true` if the type is indeed primitive.
     fn try_visit_primitive(
         &mut self,
         value: &OpTy<'tcx, M::Provenance>,
@@ -602,6 +602,7 @@ fn try_visit_primitive(
             | ty::Bound(..)
             | ty::Param(..)
             | ty::Alias(..)
+            | ty::GeneratorWitnessMIR(..)
             | ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty),
         }
     }
@@ -623,7 +624,7 @@ fn visit_scalar(
                 // Can only happen during CTFE.
                 // We support 2 kinds of ranges here: full range, and excluding zero.
                 if start == 1 && end == max_value {
-                    // Only null is the niche.  So make sure the ptr is NOT null.
+                    // Only null is the niche. So make sure the ptr is NOT null.
                     if self.ecx.scalar_may_be_null(scalar)? {
                         throw_validation_failure!(self.path,
                             { "a potentially null pointer" }
@@ -759,7 +760,7 @@ fn visit_value(&mut self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx>
         // Recursively walk the value at its type.
         self.walk_value(op)?;
 
-        // *After* all of this, check the ABI.  We need to check the ABI to handle
+        // *After* all of this, check the ABI. We need to check the ABI to handle
         // types like `NonNull` where the `Scalar` info is more restrictive than what
         // the fields say (`rustc_layout_scalar_valid_range_start`).
         // But in most cases, this will just propagate what the fields say,
@@ -857,10 +858,10 @@ fn visit_aggregate(
                 // Optimization: we just check the entire range at once.
                 // NOTE: Keep this in sync with the handling of integer and float
                 // types above, in `visit_primitive`.
-                // In run-time mode, we accept pointers in here.  This is actually more
+                // In run-time mode, we accept pointers in here. This is actually more
                 // permissive than a per-element check would be, e.g., we accept
                 // a &[u8] that contains a pointer even though bytewise checking would
-                // reject it.  However, that's good: We don't inherently want
+                // reject it. However, that's good: We don't inherently want
                 // to reject those pointers, we just do not have the machinery to
                 // talk about parts of a pointer.
                 // We also accept uninit, for consistency with the slow path.
index 1a10851a9f9013d92923c9347fac038fd14a7e17..f9efc2418dbbcd0ed5ccb8919da86b8bec11a391 100644 (file)
@@ -481,12 +481,12 @@ fn walk_value(&mut self, v: &Self::V) -> InterpResult<'tcx>
                 };
 
                 // Visit the fields of this value.
-                match v.layout().fields {
+                match &v.layout().fields {
                     FieldsShape::Primitive => {}
-                    FieldsShape::Union(fields) => {
+                    &FieldsShape::Union(fields) => {
                         self.visit_union(v, fields)?;
                     }
-                    FieldsShape::Arbitrary { ref offsets, .. } => {
+                    FieldsShape::Arbitrary { offsets, .. } => {
                         // FIXME: We collect in a vec because otherwise there are lifetime
                         // errors: Projecting to a field needs access to `ecx`.
                         let fields: Vec<InterpResult<'tcx, Self::V>> =
index 46e7b09a55e109c61f24eabb844437a13dcd1d1d..51624a0c6c817bb4a5327cd3cf1e744a75329772 100644 (file)
@@ -6,7 +6,6 @@
 
 #![feature(assert_matches)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(decl_macro)]
 #![feature(exact_size_is_empty)]
 #![feature(let_chains)]
@@ -59,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 d4c75cd55ce1e4fe89170c96bffe7fcc8b7d88b8..f47e3e86ebe2e0a0eedf3b14903e62d986c2c341 100644 (file)
@@ -442,7 +442,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
 
         self.super_rvalue(rvalue, location);
 
-        match *rvalue {
+        match rvalue {
             Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess),
 
             Rvalue::Use(_)
@@ -451,18 +451,15 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
             | Rvalue::Discriminant(..)
             | Rvalue::Len(_) => {}
 
-            Rvalue::Aggregate(ref kind, ..) => {
-                if let AggregateKind::Generator(def_id, ..) = kind.as_ref() {
-                    if let Some(generator_kind) = self.tcx.generator_kind(def_id.to_def_id()) {
-                        if matches!(generator_kind, hir::GeneratorKind::Async(..)) {
-                            self.check_op(ops::Generator(generator_kind));
-                        }
-                    }
+            Rvalue::Aggregate(kind, ..) => {
+                if let AggregateKind::Generator(def_id, ..) = kind.as_ref()
+                    && let Some(generator_kind @ hir::GeneratorKind::Async(..)) = self.tcx.generator_kind(def_id.to_def_id())
+                {
+                    self.check_op(ops::Generator(generator_kind));
                 }
             }
 
-            Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, ref place)
-            | Rvalue::Ref(_, kind @ BorrowKind::Unique, ref place) => {
+            Rvalue::Ref(_, kind @ (BorrowKind::Mut { .. } | BorrowKind::Unique), place) => {
                 let ty = place.ty(self.body, self.tcx).ty;
                 let is_allowed = match ty.kind() {
                     // Inside a `static mut`, `&mut [...]` is allowed.
@@ -491,12 +488,12 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                 }
             }
 
-            Rvalue::AddressOf(Mutability::Mut, ref place) => {
+            Rvalue::AddressOf(Mutability::Mut, place) => {
                 self.check_mut_borrow(place.local, hir::BorrowKind::Raw)
             }
 
-            Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, ref place)
-            | Rvalue::AddressOf(Mutability::Not, ref place) => {
+            Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, place)
+            | Rvalue::AddressOf(Mutability::Not, place) => {
                 let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
                     &self.ccx,
                     &mut |local| self.qualifs.has_mut_interior(self.ccx, local, location),
@@ -564,7 +561,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
             Rvalue::ShallowInitBox(_, _) => {}
 
-            Rvalue::UnaryOp(_, ref operand) => {
+            Rvalue::UnaryOp(_, operand) => {
                 let ty = operand.ty(self.body, self.tcx);
                 if is_int_bool_or_char(ty) {
                     // Int, bool, and char operations are fine.
@@ -575,8 +572,8 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                 }
             }
 
-            Rvalue::BinaryOp(op, box (ref lhs, ref rhs))
-            | Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => {
+            Rvalue::BinaryOp(op, box (lhs, rhs))
+            | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => {
                 let lhs_ty = lhs.ty(self.body, self.tcx);
                 let rhs_ty = rhs.ty(self.body, self.tcx);
 
@@ -585,13 +582,16 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                 } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() {
                     assert_eq!(lhs_ty, rhs_ty);
                     assert!(
-                        op == BinOp::Eq
-                            || op == BinOp::Ne
-                            || op == BinOp::Le
-                            || op == BinOp::Lt
-                            || op == BinOp::Ge
-                            || op == BinOp::Gt
-                            || op == BinOp::Offset
+                        matches!(
+                            op,
+                            BinOp::Eq
+                            | BinOp::Ne
+                            | BinOp::Le
+                            | BinOp::Lt
+                            | BinOp::Ge
+                            | BinOp::Gt
+                            | BinOp::Offset
+                        )
                     );
 
                     self.check_op(ops::RawPtrComparison);
@@ -693,6 +693,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
         }
     }
@@ -754,12 +755,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 54868e418c4b3f5bb5ff91c1851778598450a135..e841500bf3e0569bc2ab9202eebe6bf8b6fffd9b 100644 (file)
@@ -72,7 +72,7 @@ pub fn fn_sig(&self) -> PolyFnSig<'tcx> {
             let ty::Closure(_, substs) = ty.kind() else { bug!("type_of closure not ty::Closure") };
             substs.as_closure().sig()
         } else {
-            self.tcx.fn_sig(did)
+            self.tcx.fn_sig(did).subst_identity()
         }
     }
 }
index 04ce701452b90de0c346efd4b8c8250f0e6d76f9..fae6117f8f05224616eb95d0ed345b606b785890 100644 (file)
@@ -133,7 +133,7 @@ fn visit_local(&mut self, index: Local, context: PlaceContext, location: Locatio
                 }
                 _ => { /* mark as unpromotable below */ }
             }
-        } else if let TempState::Defined { ref mut uses, .. } = *temp {
+        } else if let TempState::Defined { uses, .. } = temp {
             // We always allow borrows, even mutable ones, as we need
             // to promote mutable borrows of some ZSTs e.g., `&mut []`.
             let allowed_use = match context {
@@ -748,7 +748,7 @@ fn promote_temp(&mut self, temp: Local) -> Local {
         if loc.statement_index < num_stmts {
             let (mut rvalue, source_info) = {
                 let statement = &mut self.source[loc.block].statements[loc.statement_index];
-                let StatementKind::Assign(box (_, ref mut rhs)) = statement.kind else {
+                let StatementKind::Assign(box (_, rhs)) = &mut statement.kind else {
                     span_bug!(
                         statement.source_info.span,
                         "{:?} is not an assignment",
@@ -778,9 +778,9 @@ fn promote_temp(&mut self, temp: Local) -> Local {
                 self.source[loc.block].terminator().clone()
             } else {
                 let terminator = self.source[loc.block].terminator_mut();
-                let target = match terminator.kind {
-                    TerminatorKind::Call { target: Some(target), .. } => target,
-                    ref kind => {
+                let target = match &terminator.kind {
+                    TerminatorKind::Call { target: Some(target), .. } => *target,
+                    kind => {
                         span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
                     }
                 };
@@ -814,7 +814,7 @@ fn promote_temp(&mut self, temp: Local) -> Local {
                         ..terminator
                     };
                 }
-                ref kind => {
+                kind => {
                     span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
                 }
             };
@@ -847,54 +847,50 @@ fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) ->
             let local_decls = &mut self.source.local_decls;
             let loc = candidate.location;
             let statement = &mut blocks[loc.block].statements[loc.statement_index];
-            match statement.kind {
-                StatementKind::Assign(box (
-                    _,
-                    Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
-                )) => {
-                    // Use the underlying local for this (necessarily interior) borrow.
-                    let ty = local_decls[place.local].ty;
-                    let span = statement.source_info.span;
-
-                    let ref_ty = tcx.mk_ref(
-                        tcx.lifetimes.re_erased,
-                        ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
-                    );
+            let StatementKind::Assign(box (_, Rvalue::Ref(region, borrow_kind, place))) = &mut statement.kind else {
+                bug!()
+            };
 
-                    *region = tcx.lifetimes.re_erased;
-
-                    let mut projection = vec![PlaceElem::Deref];
-                    projection.extend(place.projection);
-                    place.projection = tcx.intern_place_elems(&projection);
-
-                    // Create a temp to hold the promoted reference.
-                    // This is because `*r` requires `r` to be a local,
-                    // otherwise we would use the `promoted` directly.
-                    let mut promoted_ref = LocalDecl::new(ref_ty, span);
-                    promoted_ref.source_info = statement.source_info;
-                    let promoted_ref = local_decls.push(promoted_ref);
-                    assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
-
-                    let promoted_ref_statement = Statement {
-                        source_info: statement.source_info,
-                        kind: StatementKind::Assign(Box::new((
-                            Place::from(promoted_ref),
-                            Rvalue::Use(promoted_operand(ref_ty, span)),
-                        ))),
-                    };
-                    self.extra_statements.push((loc, promoted_ref_statement));
-
-                    Rvalue::Ref(
-                        tcx.lifetimes.re_erased,
-                        borrow_kind,
-                        Place {
-                            local: mem::replace(&mut place.local, promoted_ref),
-                            projection: List::empty(),
-                        },
-                    )
-                }
-                _ => bug!(),
-            }
+            // Use the underlying local for this (necessarily interior) borrow.
+            let ty = local_decls[place.local].ty;
+            let span = statement.source_info.span;
+
+            let ref_ty = tcx.mk_ref(
+                tcx.lifetimes.re_erased,
+                ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
+            );
+
+            *region = tcx.lifetimes.re_erased;
+
+            let mut projection = vec![PlaceElem::Deref];
+            projection.extend(place.projection);
+            place.projection = tcx.intern_place_elems(&projection);
+
+            // Create a temp to hold the promoted reference.
+            // This is because `*r` requires `r` to be a local,
+            // otherwise we would use the `promoted` directly.
+            let mut promoted_ref = LocalDecl::new(ref_ty, span);
+            promoted_ref.source_info = statement.source_info;
+            let promoted_ref = local_decls.push(promoted_ref);
+            assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
+
+            let promoted_ref_statement = Statement {
+                source_info: statement.source_info,
+                kind: StatementKind::Assign(Box::new((
+                    Place::from(promoted_ref),
+                    Rvalue::Use(promoted_operand(ref_ty, span)),
+                ))),
+            };
+            self.extra_statements.push((loc, promoted_ref_statement));
+
+            Rvalue::Ref(
+                tcx.lifetimes.re_erased,
+                *borrow_kind,
+                Place {
+                    local: mem::replace(&mut place.local, promoted_ref),
+                    projection: List::empty(),
+                },
+            )
         };
 
         assert_eq!(self.new_block(), START_BLOCK);
index 94e1b95a0eb3c9501a33f4d3bafecd82c632bd9f..a2f2457487a4fc35974cb12a8f9e9e8af998320e 100644 (file)
@@ -1,7 +1,8 @@
 //! Validates the MIR to ensure that invariants are upheld.
 
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
 use rustc_infer::traits::Reveal;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
     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};
 use rustc_target::abi::{Size, VariantIdx};
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 enum EdgeKind {
     Unwind,
     Normal,
@@ -57,18 +58,20 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             .iterate_to_fixpoint()
             .into_results_cursor(body);
 
-        TypeChecker {
+        let mut checker = TypeChecker {
             when: &self.when,
             body,
             tcx,
             param_env,
             mir_phase,
+            unwind_edge_count: 0,
             reachable_blocks: traversal::reachable_as_bitset(body),
             storage_liveness,
             place_cache: Vec::new(),
             value_cache: Vec::new(),
-        }
-        .visit_body(body);
+        };
+        checker.visit_body(body);
+        checker.check_cleanup_control_flow();
     }
 }
 
@@ -78,6 +81,7 @@ struct TypeChecker<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
     mir_phase: MirPhase,
+    unwind_edge_count: usize,
     reachable_blocks: BitSet<BasicBlock>,
     storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>,
     place_cache: Vec<PlaceRef<'tcx>>,
@@ -102,7 +106,7 @@ fn fail(&self, location: Location, msg: impl AsRef<str>) {
         );
     }
 
-    fn check_edge(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
+    fn check_edge(&mut self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
         if bb == START_BLOCK {
             self.fail(location, "start block must not have predecessors")
         }
@@ -111,10 +115,12 @@ fn check_edge(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
             match (src.is_cleanup, bb.is_cleanup, edge_kind) {
                 // Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges
                 (false, false, EdgeKind::Normal)
-                // Non-cleanup blocks can jump to cleanup blocks along unwind edges
-                | (false, true, EdgeKind::Unwind)
                 // Cleanup blocks can jump to cleanup blocks along non-unwind edges
                 | (true, true, EdgeKind::Normal) => {}
+                // Non-cleanup blocks can jump to cleanup blocks along unwind edges
+                (false, true, EdgeKind::Unwind) => {
+                    self.unwind_edge_count += 1;
+                }
                 // All other jumps are invalid
                 _ => {
                     self.fail(
@@ -134,6 +140,88 @@ fn check_edge(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
         }
     }
 
+    fn check_cleanup_control_flow(&self) {
+        if self.unwind_edge_count <= 1 {
+            return;
+        }
+        let doms = self.body.basic_blocks.dominators();
+        let mut post_contract_node = FxHashMap::default();
+        // Reusing the allocation across invocations of the closure
+        let mut dom_path = vec![];
+        let mut get_post_contract_node = |mut bb| {
+            let root = loop {
+                if let Some(root) = post_contract_node.get(&bb) {
+                    break *root;
+                }
+                let parent = doms.immediate_dominator(bb);
+                dom_path.push(bb);
+                if !self.body.basic_blocks[parent].is_cleanup {
+                    break bb;
+                }
+                bb = parent;
+            };
+            for bb in dom_path.drain(..) {
+                post_contract_node.insert(bb, root);
+            }
+            root
+        };
+
+        let mut parent = IndexVec::from_elem(None, &self.body.basic_blocks);
+        for (bb, bb_data) in self.body.basic_blocks.iter_enumerated() {
+            if !bb_data.is_cleanup || !self.reachable_blocks.contains(bb) {
+                continue;
+            }
+            let bb = get_post_contract_node(bb);
+            for s in bb_data.terminator().successors() {
+                let s = get_post_contract_node(s);
+                if s == bb {
+                    continue;
+                }
+                let parent = &mut parent[bb];
+                match parent {
+                    None => {
+                        *parent = Some(s);
+                    }
+                    Some(e) if *e == s => (),
+                    Some(e) => self.fail(
+                        Location { block: bb, statement_index: 0 },
+                        format!(
+                            "Cleanup control flow violation: The blocks dominated by {:?} have edges to both {:?} and {:?}",
+                            bb,
+                            s,
+                            *e
+                        )
+                    ),
+                }
+            }
+        }
+
+        // Check for cycles
+        let mut stack = FxHashSet::default();
+        for i in 0..parent.len() {
+            let mut bb = BasicBlock::from_usize(i);
+            stack.clear();
+            stack.insert(bb);
+            loop {
+                let Some(parent)= parent[bb].take() else {
+                    break
+                };
+                let no_cycle = stack.insert(parent);
+                if !no_cycle {
+                    self.fail(
+                        Location { block: bb, statement_index: 0 },
+                        format!(
+                            "Cleanup control flow violation: Cycle involving edge {:?} -> {:?}",
+                            bb, parent,
+                        ),
+                    );
+                    break;
+                }
+                bb = parent;
+            }
+        }
+    }
+
     /// Check if src can be assigned into dest.
     /// This is not precise, it will accept some incorrect assignments.
     fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
@@ -142,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)
     }
@@ -289,12 +372,12 @@ fn visit_projection_elem(
                                 return;
                             };
 
-                            let Some(&f_ty) = layout.field_tys.get(local) else {
+                            let Some(f_ty) = layout.field_tys.get(local) else {
                                 self.fail(location, format!("Out of bounds local {:?} for {:?}", local, parent_ty));
                                 return;
                             };
 
-                            f_ty
+                            f_ty.ty
                         } else {
                             let Some(f_ty) = substs.as_generator().prefix_tys().nth(f.index()) else {
                                 fail_out_of_bounds(self, location);
@@ -678,6 +761,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             StatementKind::StorageLive(..)
             | StatementKind::StorageDead(..)
             | StatementKind::Coverage(_)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
         }
 
index 38d9b044981cd723687c8962d06345fc226aa39a..995363c0edd92e3e4849b045328b1650ec1225d1 100644 (file)
@@ -40,6 +40,7 @@ pub enum CallKind<'tcx> {
         self_arg: Option<Ident>,
         desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>,
         method_did: DefId,
+        method_substs: SubstsRef<'tcx>,
     },
     /// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)`
     FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> },
@@ -131,6 +132,6 @@ pub fn call_kind<'tcx>(
         } else {
             None
         };
-        CallKind::Normal { self_arg, desugaring, method_did }
+        CallKind::Normal { self_arg, desugaring, method_did, method_substs }
     })
 }
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 c4122f66498143a70950219d6afb696c91d58f40..4e80a28518668ef10f9f77971f281fb069abd557 100644 (file)
@@ -64,6 +64,7 @@ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
             ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
 
             ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"),
+            ty::GeneratorWitnessMIR(..) => bug!("type_name: unexpected `GeneratorWitnessMIR`"),
         }
     }
 
index c81e1b124f0e5f02eb4ddb904e7d97a41856226d..73190574667f32135a490a3f717a777c72037793 100644 (file)
@@ -36,7 +36,7 @@
 //! ```
 //!
 //! `Frozen` impls `Deref`, so we can ergonomically call methods on `Bar`, but it doesn't `impl
-//! DerefMut`.  Now calling `foo.compute.mutate()` will result in a compile-time error stating that
+//! DerefMut`. Now calling `foo.compute.mutate()` will result in a compile-time error stating that
 //! `mutate` requires a mutable reference but we don't have one.
 //!
 //! # Caveats
index 0d0c51b6819460f58ddfd8f8faec421d451f6829..9fce0e1e65cc90f416fe8fa228a861796a51a5d9 100644 (file)
@@ -11,8 +11,8 @@
 #[macro_export]
 macro_rules! define_id_collections {
     ($map_name:ident, $set_name:ident, $entry_name:ident, $key:ty) => {
-        pub type $map_name<T> = $crate::fx::FxHashMap<$key, T>;
-        pub type $set_name = $crate::fx::FxHashSet<$key>;
+        pub type $map_name<T> = $crate::unord::UnordMap<$key, T>;
+        pub type $set_name = $crate::unord::UnordSet<$key>;
         pub type $entry_name<'a, T> = $crate::fx::StdEntry<'a, $key, T>;
     };
 }
index ea2a4388b92f00296193d9403601669f9b5379cc..0a21a4249c8295b94ab4b2f7db068a58e8da9ba7 100644 (file)
@@ -135,7 +135,50 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
         // This loop computes the semi[w] for w.
         semi[w] = w;
         for v in graph.predecessors(pre_order_to_real[w]) {
-            let v = real_to_pre_order[v].unwrap();
+            // TL;DR: Reachable vertices may have unreachable predecessors, so ignore any of them.
+            //
+            // Ignore blocks which are not connected to the entry block.
+            //
+            // The algorithm that was used to traverse the graph and build the
+            // `pre_order_to_real` and `real_to_pre_order` vectors does so by
+            // starting from the entry block and following the successors.
+            // Therefore, any blocks not reachable from the entry block will be
+            // set to `None` in the `pre_order_to_real` vector.
+            //
+            // For example, in this graph, A and B should be skipped:
+            //
+            //           ┌─────┐
+            //           │     │
+            //           └──┬──┘
+            //              │
+            //           ┌──▼──┐              ┌─────┐
+            //           │     │              │  A  │
+            //           └──┬──┘              └──┬──┘
+            //              │                    │
+            //      ┌───────┴───────┐            │
+            //      │               │            │
+            //   ┌──▼──┐         ┌──▼──┐      ┌──▼──┐
+            //   │     │         │     │      │  B  │
+            //   └──┬──┘         └──┬──┘      └──┬──┘
+            //      │               └──────┬─────┘
+            //   ┌──▼──┐                   │
+            //   │     │                   │
+            //   └──┬──┘                ┌──▼──┐
+            //      │                   │     │
+            //      │                   └─────┘
+            //   ┌──▼──┐
+            //   │     │
+            //   └──┬──┘
+            //      │
+            //   ┌──▼──┐
+            //   │     │
+            //   └─────┘
+            //
+            // ...this may be the case if a MirPass modifies the CFG to remove
+            // or rearrange certain blocks/edges.
+            let Some(v) = real_to_pre_order[v] else {
+                continue
+            };
 
             // eval returns a vertex x from which semi[x] is minimum among
             // vertices semi[v] +> x *> v.
@@ -261,17 +304,18 @@ fn compress(
     }
 }
 
+/// Tracks the list of dominators for each node.
 #[derive(Clone, Debug)]
 pub struct Dominators<N: Idx> {
     post_order_rank: IndexVec<N, usize>,
+    // Even though we track only the immediate dominator of each node, it's
+    // possible to get its full list of dominators by looking up the dominator
+    // of each dominator. (See the `impl Iterator for Iter` definition).
     immediate_dominators: IndexVec<N, Option<N>>,
 }
 
 impl<Node: Idx> Dominators<Node> {
-    pub fn dummy() -> Self {
-        Self { post_order_rank: IndexVec::new(), immediate_dominators: IndexVec::new() }
-    }
-
+    /// Whether the given Node has an immediate dominator.
     pub fn is_reachable(&self, node: Node) -> bool {
         self.immediate_dominators[node].is_some()
     }
@@ -281,12 +325,14 @@ pub fn immediate_dominator(&self, node: Node) -> Node {
         self.immediate_dominators[node].unwrap()
     }
 
+    /// Provides an iterator over each dominator up the CFG, for the given Node.
+    /// See the `impl Iterator for Iter` definition to understand how this works.
     pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
         assert!(self.is_reachable(node), "node {node:?} is not reachable");
         Iter { dominators: self, node: Some(node) }
     }
 
-    pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool {
+    pub fn dominates(&self, dom: Node, node: Node) -> bool {
         // FIXME -- could be optimized by using post-order-rank
         self.dominators(node).any(|n| n == dom)
     }
@@ -296,7 +342,7 @@ pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool {
     /// of two unrelated nodes will also be consistent, but otherwise the order has no
     /// meaning.) This method cannot be used to determine if either Node dominates the other.
     pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> {
-        self.post_order_rank[lhs].partial_cmp(&self.post_order_rank[rhs])
+        self.post_order_rank[rhs].partial_cmp(&self.post_order_rank[lhs])
     }
 }
 
index e4e4d0d44babaa231055d95c5702d94ca9bf2429..dc1ce1747bfa0dc1d6def1306db79460d3e907f9 100644 (file)
@@ -70,8 +70,8 @@ fn test_adjacent_edges<N: PartialEq + Debug, E: PartialEq + Debug>(
             "counter={:?} expected={:?} edge_index={:?} edge={:?}",
             counter, expected_incoming[counter], edge_index, edge
         );
-        match expected_incoming[counter] {
-            (ref e, ref n) => {
+        match &expected_incoming[counter] {
+            (e, n) => {
                 assert!(e == &edge.data);
                 assert!(n == graph.node_data(edge.source()));
                 assert!(start_index == edge.target);
@@ -88,8 +88,8 @@ fn test_adjacent_edges<N: PartialEq + Debug, E: PartialEq + Debug>(
             "counter={:?} expected={:?} edge_index={:?} edge={:?}",
             counter, expected_outgoing[counter], edge_index, edge
         );
-        match expected_outgoing[counter] {
-            (ref e, ref n) => {
+        match &expected_outgoing[counter] {
+            (e, n) => {
                 assert!(e == &edge.data);
                 assert!(start_index == edge.source);
                 assert!(n == graph.node_data(edge.target));
index 57007611a76c3b3d12a4fe43142eb2e3c775d284..8a9af300c066ef2ba1cfed4e9ef73e8606c77f9a 100644 (file)
@@ -317,12 +317,12 @@ fn node_examined(
         _node: G::Node,
         _prior_status: Option<NodeStatus>,
     ) -> ControlFlow<Self::BreakVal> {
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 
     /// Called after all nodes reachable from this one have been examined.
     fn node_settled(&mut self, _node: G::Node) -> ControlFlow<Self::BreakVal> {
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 
     /// Behave as if no edges exist from `source` to `target`.
@@ -346,8 +346,8 @@ fn node_examined(
         prior_status: Option<NodeStatus>,
     ) -> ControlFlow<Self::BreakVal> {
         match prior_status {
-            Some(NodeStatus::Visited) => ControlFlow::BREAK,
-            _ => ControlFlow::CONTINUE,
+            Some(NodeStatus::Visited) => ControlFlow::Break(()),
+            _ => ControlFlow::Continue(()),
         }
     }
 }
index 9940fee60d7d8209a56a988a0bb52278d434302b..820a70fc8e446c8094763ee5ad25db9f3e9c6cc9 100644 (file)
@@ -84,7 +84,7 @@ fn test_find_state_2() {
     // 0 -> 1 -> 2 -> 1
     //
     // and at this point detect a cycle. The state of 2 will thus be
-    // `InCycleWith { 1 }`.  We will then visit the 1 -> 3 edge, which
+    // `InCycleWith { 1 }`. We will then visit the 1 -> 3 edge, which
     // will attempt to visit 0 as well, thus going to the state
     // `InCycleWith { 0 }`. Finally, node 1 will complete; the lowest
     // depth of any successor was 3 which had depth 0, and thus it
index 3a2000233c5d10fac7150e1956b2e33f7a9a7042..954e84c303b83d031cc4b2be76c56b4e90e1cea1 100644 (file)
@@ -11,7 +11,6 @@
 #![feature(associated_type_bounds)]
 #![feature(auto_traits)]
 #![feature(cell_leak)]
-#![feature(control_flow_enum)]
 #![feature(extend_one)]
 #![feature(hash_raw_entry)]
 #![feature(hasher_prefixfree_extras)]
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 c63caa06818f26e2f3f263d778c140ae5fc588aa..9409057d4847e419b8960e0a389d6341f7a6d192 100644 (file)
@@ -1,6 +1,5 @@
 use crate::stable_hasher::{HashStable, StableHasher, StableOrd};
 use std::borrow::Borrow;
-use std::cmp::Ordering;
 use std::fmt::Debug;
 use std::mem;
 use std::ops::{Bound, Index, IndexMut, RangeBounds};
@@ -171,7 +170,7 @@ pub fn offset_keys<F>(&mut self, f: F)
     where
         F: Fn(&mut K),
     {
-        self.data.iter_mut().map(|&mut (ref mut k, _)| k).for_each(f);
+        self.data.iter_mut().map(|(k, _)| k).for_each(f);
     }
 
     /// Inserts a presorted range of elements into the map. If the range can be
@@ -232,10 +231,10 @@ fn range_slice_indices<R>(&self, range: R) -> (usize, usize)
         R: RangeBounds<K>,
     {
         let start = match range.start_bound() {
-            Bound::Included(ref k) => match self.lookup_index_for(k) {
+            Bound::Included(k) => match self.lookup_index_for(k) {
                 Ok(index) | Err(index) => index,
             },
-            Bound::Excluded(ref k) => match self.lookup_index_for(k) {
+            Bound::Excluded(k) => match self.lookup_index_for(k) {
                 Ok(index) => index + 1,
                 Err(index) => index,
             },
@@ -243,11 +242,11 @@ fn range_slice_indices<R>(&self, range: R) -> (usize, usize)
         };
 
         let end = match range.end_bound() {
-            Bound::Included(ref k) => match self.lookup_index_for(k) {
+            Bound::Included(k) => match self.lookup_index_for(k) {
                 Ok(index) => index + 1,
                 Err(index) => index,
             },
-            Bound::Excluded(ref k) => match self.lookup_index_for(k) {
+            Bound::Excluded(k) => match self.lookup_index_for(k) {
                 Ok(index) | Err(index) => index,
             },
             Bound::Unbounded => self.data.len(),
@@ -302,7 +301,7 @@ fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
         let mut data: Vec<(K, V)> = iter.into_iter().collect();
 
         data.sort_unstable_by(|(k1, _), (k2, _)| k1.cmp(k2));
-        data.dedup_by(|&mut (ref k1, _), &mut (ref k2, _)| k1.cmp(k2) == Ordering::Equal);
+        data.dedup_by(|(k1, _), (k2, _)| k1 == k2);
 
         SortedMap { data }
     }
index 7af5c14942adf8c30ac0c0bc898655b97251a708..814e7c7fb9ba6751aa9dbe368319bd5525df3c17 100644 (file)
@@ -63,13 +63,13 @@ pub fn into_iter_enumerated(self) -> impl DoubleEndedIterator<Item = (I, (K, V))
     /// Returns an iterator over the items in the map in insertion order.
     #[inline]
     pub fn iter(&self) -> impl '_ + DoubleEndedIterator<Item = (&K, &V)> {
-        self.items.iter().map(|(ref k, ref v)| (k, v))
+        self.items.iter().map(|(k, v)| (k, v))
     }
 
     /// Returns an iterator over the items in the map in insertion order along with their indices.
     #[inline]
     pub fn iter_enumerated(&self) -> impl '_ + DoubleEndedIterator<Item = (I, (&K, &V))> {
-        self.items.iter_enumerated().map(|(i, (ref k, ref v))| (i, (k, v)))
+        self.items.iter_enumerated().map(|(i, (k, v))| (i, (k, v)))
     }
 
     /// Returns the item in the map with the given index.
index 1e977d709f1cdae35699717160e0c29b97c973da..3cc250862df42bb39b28688d564a929d400a7cc7 100644 (file)
@@ -6,7 +6,7 @@ fn test_sorted_index_multi_map() {
     let set: SortedIndexMultiMap<usize, _, _> = entries.iter().copied().collect();
 
     // Insertion order is preserved.
-    assert!(entries.iter().map(|(ref k, ref v)| (k, v)).eq(set.iter()));
+    assert!(entries.iter().map(|(k, v)| (k, v)).eq(set.iter()));
 
     // Indexing
     for (i, expect) in entries.iter().enumerate() {
index 9b07f86846eb32089b26b5834dcdb72ab0b29e9e..11a408f216a1465ca4335fa7879a342a82ff61ae 100644 (file)
@@ -37,9 +37,9 @@ pub fn insert(&mut self, data: T) {
 
     #[inline]
     pub fn remove(&mut self, data: &T) -> bool {
-        self.head = match self.head {
-            Some(ref mut head) if head.data == *data => head.next.take().map(|x| *x),
-            Some(ref mut head) => return head.remove_next(data),
+        self.head = match &mut self.head {
+            Some(head) if head.data == *data => head.next.take().map(|x| *x),
+            Some(head) => return head.remove_next(data),
             None => return false,
         };
         true
@@ -48,7 +48,7 @@ pub fn remove(&mut self, data: &T) -> bool {
     #[inline]
     pub fn contains(&self, data: &T) -> bool {
         let mut elem = self.head.as_ref();
-        while let Some(ref e) = elem {
+        while let Some(e) = elem {
             if &e.data == data {
                 return true;
             }
@@ -65,15 +65,14 @@ struct Element<T> {
 }
 
 impl<T: PartialEq> Element<T> {
-    fn remove_next(&mut self, data: &T) -> bool {
-        let mut n = self;
+    fn remove_next(mut self: &mut Self, data: &T) -> bool {
         loop {
-            match n.next {
+            match self.next {
                 Some(ref mut next) if next.data == *data => {
-                    n.next = next.next.take();
+                    self.next = next.next.take();
                     return true;
                 }
-                Some(ref mut next) => n = next,
+                Some(ref mut next) => self = next,
                 None => return false,
             }
         }
index c0334d2e23e5544d62f6790733c6d95b91c1853d..4b95e62bef02b1391af37c41a4e9823bec5b3983 100644 (file)
@@ -6,7 +6,7 @@
 impl<T> TinyList<T> {
     fn len(&self) -> usize {
         let (mut elem, mut count) = (self.head.as_ref(), 0);
-        while let Some(ref e) = elem {
+        while let Some(e) = elem {
             count += 1;
             elem = e.next.as_deref();
         }
index 1ff0d58df140907129ac3d97d39a81ee10a3e630..cd391fe357a6f0b76f9975649bd6898fe547bf43 100644 (file)
@@ -250,7 +250,7 @@ pub fn minimal_upper_bounds(&self, a: T, b: T) -> Vec<T> {
             // values. So here is what we do:
             //
             // 1. Find the vector `[X | a < X && b < X]` of all values
-            //    `X` where `a < X` and `b < X`.  In terms of the
+            //    `X` where `a < X` and `b < X`. In terms of the
             //    graph, this means all values reachable from both `a`
             //    and `b`. Note that this vector is also a set, but we
             //    use the term vector because the order matters
index 14257e4d5c60b8c1ccbd5c40b89267b0162d19eb..f35f18e51cb4e5339dfd8a4b88b9c291ce773256 100644 (file)
@@ -6,13 +6,15 @@
 use smallvec::SmallVec;
 use std::{
     borrow::Borrow,
+    collections::hash_map::Entry,
     hash::Hash,
     iter::{Product, Sum},
+    ops::Index,
 };
 
 use crate::{
     fingerprint::Fingerprint,
-    stable_hasher::{HashStable, StableHasher, ToStableHashKey},
+    stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey},
 };
 
 /// `UnordItems` is the order-less version of `Iterator`. It only contains methods
@@ -38,17 +40,17 @@ pub fn map<U, F: Fn(T) -> U>(self, f: F) -> UnordItems<U, impl Iterator<Item = U
     }
 
     #[inline]
-    pub fn all<U, F: Fn(T) -> bool>(mut self, f: F) -> bool {
+    pub fn all<F: Fn(T) -> bool>(mut self, f: F) -> bool {
         self.0.all(f)
     }
 
     #[inline]
-    pub fn any<U, F: Fn(T) -> bool>(mut self, f: F) -> bool {
+    pub fn any<F: Fn(T) -> bool>(mut self, f: F) -> bool {
         self.0.any(f)
     }
 
     #[inline]
-    pub fn filter<U, F: Fn(&T) -> bool>(self, f: F) -> UnordItems<T, impl Iterator<Item = T>> {
+    pub fn filter<F: Fn(&T) -> bool>(self, f: F) -> UnordItems<T, impl Iterator<Item = T>> {
         UnordItems(self.0.filter(f))
     }
 
@@ -96,6 +98,15 @@ pub fn product<S>(self) -> S
     pub fn count(self) -> usize {
         self.0.count()
     }
+
+    #[inline]
+    pub fn flat_map<U, F, O>(self, f: F) -> UnordItems<O, impl Iterator<Item = O>>
+    where
+        U: IntoIterator<Item = O>,
+        F: Fn(T) -> U,
+    {
+        UnordItems(self.0.flat_map(f))
+    }
 }
 
 impl<'a, T: Clone + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> {
@@ -147,6 +158,7 @@ pub struct UnordSet<V: Eq + Hash> {
 }
 
 impl<V: Eq + Hash> Default for UnordSet<V> {
+    #[inline]
     fn default() -> Self {
         Self { inner: FxHashSet::default() }
     }
@@ -178,7 +190,16 @@ pub fn contains<Q: ?Sized>(&self, v: &Q) -> bool
     }
 
     #[inline]
-    pub fn items(&self) -> UnordItems<&V, impl Iterator<Item = &V>> {
+    pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> bool
+    where
+        V: Borrow<Q>,
+        Q: Hash + Eq,
+    {
+        self.inner.remove(k)
+    }
+
+    #[inline]
+    pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator<Item = &'a V>> {
         UnordItems(self.inner.iter())
     }
 
@@ -187,20 +208,75 @@ pub fn into_items(self) -> UnordItems<V, impl Iterator<Item = V>> {
         UnordItems(self.inner.into_iter())
     }
 
+    /// Returns the items of this set in stable sort order (as defined by `ToStableHashKey`).
+    ///
+    /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or
+    /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use
+    /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation
+    /// for `V` is expensive (e.g. a `DefId -> DefPathHash` lookup).
+    #[inline]
+    pub fn to_sorted<HCX>(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<&V>
+    where
+        V: ToStableHashKey<HCX>,
+    {
+        to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&x| x)
+    }
+
+    /// Returns the items of this set in stable sort order (as defined by
+    /// `StableOrd`). This method is much more efficient than
+    /// `into_sorted` because it does not need to transform keys to their
+    /// `ToStableHashKey` equivalent.
+    #[inline]
+    pub fn to_sorted_stable_ord(&self) -> Vec<V>
+    where
+        V: Ord + StableOrd + Copy,
+    {
+        let mut items: Vec<V> = self.inner.iter().copied().collect();
+        items.sort_unstable();
+        items
+    }
+
+    /// Returns the items of this set in stable sort order (as defined by `ToStableHashKey`).
+    ///
+    /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or
+    /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use
+    /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation
+    /// for `V` is expensive (e.g. a `DefId -> DefPathHash` lookup).
+    #[inline]
+    pub fn into_sorted<HCX>(self, hcx: &HCX, cache_sort_key: bool) -> Vec<V>
+    where
+        V: ToStableHashKey<HCX>,
+    {
+        to_sorted_vec(hcx, self.inner.into_iter(), cache_sort_key, |x| x)
+    }
+
     // We can safely extend this UnordSet from a set of unordered values because that
     // won't expose the internal ordering anywhere.
     #[inline]
     pub fn extend<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) {
         self.inner.extend(items.0)
     }
+
+    #[inline]
+    pub fn clear(&mut self) {
+        self.inner.clear();
+    }
 }
 
 impl<V: Hash + Eq> Extend<V> for UnordSet<V> {
+    #[inline]
     fn extend<T: IntoIterator<Item = V>>(&mut self, iter: T) {
         self.inner.extend(iter)
     }
 }
 
+impl<V: Hash + Eq> FromIterator<V> for UnordSet<V> {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
+        UnordSet { inner: FxHashSet::from_iter(iter) }
+    }
+}
+
 impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordSet<V> {
     #[inline]
     fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
@@ -223,17 +299,33 @@ pub struct UnordMap<K: Eq + Hash, V> {
 }
 
 impl<K: Eq + Hash, V> Default for UnordMap<K, V> {
+    #[inline]
     fn default() -> Self {
         Self { inner: FxHashMap::default() }
     }
 }
 
 impl<K: Hash + Eq, V> Extend<(K, V)> for UnordMap<K, V> {
+    #[inline]
     fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
         self.inner.extend(iter)
     }
 }
 
+impl<K: Hash + Eq, V> FromIterator<(K, V)> for UnordMap<K, V> {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
+        UnordMap { inner: FxHashMap::from_iter(iter) }
+    }
+}
+
+impl<K: Hash + Eq, V, I: Iterator<Item = (K, V)>> From<UnordItems<(K, V), I>> for UnordMap<K, V> {
+    #[inline]
+    fn from(items: UnordItems<(K, V), I>) -> Self {
+        UnordMap { inner: FxHashMap::from_iter(items.0) }
+    }
+}
+
 impl<K: Eq + Hash, V> UnordMap<K, V> {
     #[inline]
     pub fn len(&self) -> usize {
@@ -255,7 +347,44 @@ pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
     }
 
     #[inline]
-    pub fn items(&self) -> UnordItems<(&K, &V), impl Iterator<Item = (&K, &V)>> {
+    pub fn is_empty(&self) -> bool {
+        self.inner.is_empty()
+    }
+
+    #[inline]
+    pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
+        self.inner.entry(key)
+    }
+
+    #[inline]
+    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
+    where
+        K: Borrow<Q>,
+        Q: Hash + Eq,
+    {
+        self.inner.get(k)
+    }
+
+    #[inline]
+    pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
+    where
+        K: Borrow<Q>,
+        Q: Hash + Eq,
+    {
+        self.inner.get_mut(k)
+    }
+
+    #[inline]
+    pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
+    where
+        K: Borrow<Q>,
+        Q: Hash + Eq,
+    {
+        self.inner.remove(k)
+    }
+
+    #[inline]
+    pub fn items<'a>(&'a self) -> UnordItems<(&'a K, &'a V), impl Iterator<Item = (&'a K, &'a V)>> {
         UnordItems(self.inner.iter())
     }
 
@@ -270,6 +399,77 @@ pub fn into_items(self) -> UnordItems<(K, V), impl Iterator<Item = (K, V)>> {
     pub fn extend<I: Iterator<Item = (K, V)>>(&mut self, items: UnordItems<(K, V), I>) {
         self.inner.extend(items.0)
     }
+
+    /// Returns the entries of this map in stable sort order (as defined by `ToStableHashKey`).
+    ///
+    /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or
+    /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use
+    /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation
+    /// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup).
+    #[inline]
+    pub fn to_sorted<HCX>(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<(&K, &V)>
+    where
+        K: ToStableHashKey<HCX>,
+    {
+        to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&(k, _)| k)
+    }
+
+    /// Returns the entries of this map in stable sort order (as defined by `StableOrd`).
+    /// This method can be much more efficient than `into_sorted` because it does not need
+    /// to transform keys to their `ToStableHashKey` equivalent.
+    #[inline]
+    pub fn to_sorted_stable_ord(&self) -> Vec<(K, &V)>
+    where
+        K: Ord + StableOrd + Copy,
+    {
+        let mut items: Vec<(K, &V)> = self.inner.iter().map(|(&k, v)| (k, v)).collect();
+        items.sort_unstable_by_key(|&(k, _)| k);
+        items
+    }
+
+    /// Returns the entries of this map in stable sort order (as defined by `ToStableHashKey`).
+    ///
+    /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or
+    /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use
+    /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation
+    /// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup).
+    #[inline]
+    pub fn into_sorted<HCX>(self, hcx: &HCX, cache_sort_key: bool) -> Vec<(K, V)>
+    where
+        K: ToStableHashKey<HCX>,
+    {
+        to_sorted_vec(hcx, self.inner.into_iter(), cache_sort_key, |(k, _)| k)
+    }
+
+    /// Returns the values of this map in stable sort order (as defined by K's
+    /// `ToStableHashKey` implementation).
+    ///
+    /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or
+    /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use
+    /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation
+    /// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup).
+    #[inline]
+    pub fn values_sorted<HCX>(&self, hcx: &HCX, cache_sort_key: bool) -> impl Iterator<Item = &V>
+    where
+        K: ToStableHashKey<HCX>,
+    {
+        to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&(k, _)| k)
+            .into_iter()
+            .map(|(_, v)| v)
+    }
+}
+
+impl<K, Q: ?Sized, V> Index<&Q> for UnordMap<K, V>
+where
+    K: Eq + Hash + Borrow<Q>,
+    Q: Eq + Hash,
+{
+    type Output = V;
+
+    #[inline]
+    fn index(&self, key: &Q) -> &V {
+        &self.inner[key]
+    }
 }
 
 impl<HCX, K: Hash + Eq + HashStable<HCX>, V: HashStable<HCX>> HashStable<HCX> for UnordMap<K, V> {
@@ -334,6 +534,12 @@ fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
     }
 }
 
+impl<T, I: Iterator<Item = T>> From<UnordItems<T, I>> for UnordBag<T> {
+    fn from(value: UnordItems<T, I>) -> Self {
+        UnordBag { inner: Vec::from_iter(value.0) }
+    }
+}
+
 impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordBag<V> {
     #[inline]
     fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
@@ -341,6 +547,27 @@ fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
     }
 }
 
+#[inline]
+fn to_sorted_vec<HCX, T, K, I>(
+    hcx: &HCX,
+    iter: I,
+    cache_sort_key: bool,
+    extract_key: fn(&T) -> &K,
+) -> Vec<T>
+where
+    I: Iterator<Item = T>,
+    K: ToStableHashKey<HCX>,
+{
+    let mut items: Vec<T> = iter.collect();
+    if cache_sort_key {
+        items.sort_by_cached_key(|x| extract_key(x).to_stable_hash_key(hcx));
+    } else {
+        items.sort_unstable_by_key(|x| extract_key(x).to_stable_hash_key(hcx));
+    }
+
+    items
+}
+
 fn hash_iter_order_independent<
     HCX,
     T: HashStable<HCX>,
index 37dc7f6ba5fe4b06d1654ee4e686ecb7ce60e577..6d7fba36fb3d071f182ab20a105e485a0f2efc47 100644 (file)
@@ -1,5 +1,5 @@
 The `driver` crate is effectively the "main" function for the rust
-compiler.  It orchestrates the compilation process and "knits together"
+compiler. It orchestrates the compilation process and "knits together"
 the code from the other crates within rustc. This crate itself does
 not contain any of the "main logic" of the compiler (though it does
 have some code related to pretty printing or other minor compiler
index a62e5dec4b8643aba7ebc69ff4ffc5c6e67e1db5..ccefd6adaf14b6012a614e96368d46b83919a3ad 100644 (file)
@@ -219,7 +219,6 @@ fn run_compiler(
         crate_cfg: cfg,
         crate_check_cfg: check_cfg,
         input: Input::File(PathBuf::new()),
-        input_path: None,
         output_file: ofile,
         output_dir: odir,
         file_loader,
@@ -237,9 +236,8 @@ fn run_compiler(
 
     match make_input(config.opts.error_format, &matches.free) {
         Err(reported) => return Err(reported),
-        Ok(Some((input, input_file_path))) => {
+        Ok(Some(input)) => {
             config.input = input;
-            config.input_path = input_file_path;
 
             callbacks.config(&mut config);
         }
@@ -261,14 +259,8 @@ fn run_compiler(
                         describe_lints(compiler.session(), &lint_store, registered_lints);
                         return;
                     }
-                    let should_stop = print_crate_info(
-                        &***compiler.codegen_backend(),
-                        compiler.session(),
-                        None,
-                        compiler.output_dir(),
-                        compiler.output_file(),
-                        compiler.temps_dir(),
-                    );
+                    let should_stop =
+                        print_crate_info(&***compiler.codegen_backend(), compiler.session(), false);
 
                     if should_stop == Compilation::Stop {
                         return;
@@ -290,18 +282,9 @@ fn run_compiler(
 
     interface::run_compiler(config, |compiler| {
         let sess = compiler.session();
-        let should_stop = print_crate_info(
-            &***compiler.codegen_backend(),
-            sess,
-            Some(compiler.input()),
-            compiler.output_dir(),
-            compiler.output_file(),
-            compiler.temps_dir(),
-        )
-        .and_then(|| {
-            list_metadata(sess, &*compiler.codegen_backend().metadata_loader(), compiler.input())
-        })
-        .and_then(|| try_process_rlink(sess, compiler));
+        let should_stop = print_crate_info(&***compiler.codegen_backend(), sess, true)
+            .and_then(|| list_metadata(sess, &*compiler.codegen_backend().metadata_loader()))
+            .and_then(|| try_process_rlink(sess, compiler));
 
         if should_stop == Compilation::Stop {
             return sess.compile_status();
@@ -313,26 +296,13 @@ 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,
-                            compiler.input(),
-                            &*expanded_crate,
-                            *ppm,
-                            compiler.output_file().as_deref(),
-                        );
+                        pretty::print_after_hir_lowering(tcx, *ppm);
                         Ok(())
                     })?;
                 } else {
                     let krate = queries.parse()?.steal();
-                    pretty::print_after_parsing(
-                        sess,
-                        compiler.input(),
-                        &krate,
-                        *ppm,
-                        compiler.output_file().as_deref(),
-                    );
+                    pretty::print_after_parsing(sess, &krate, *ppm);
                 }
                 trace!("finished pretty-printing");
                 return early_exit();
@@ -357,12 +327,14 @@ fn run_compiler(
                 }
             }
 
-            queries.expansion()?;
+            let mut gctxt = queries.global_ctxt()?;
             if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
 
-            queries.prepare_outputs()?;
+            // 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
@@ -370,13 +342,11 @@ fn run_compiler(
                 return early_exit();
             }
 
-            queries.global_ctxt()?;
-
             if sess.opts.unstable_opts.no_analysis {
                 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);
@@ -384,15 +354,17 @@ fn run_compiler(
                         save::process_crate(
                             tcx,
                             crate_name,
-                            compiler.input(),
+                            &sess.io.input,
                             None,
-                            DumpHandler::new(compiler.output_dir().as_deref(), crate_name),
+                            DumpHandler::new(sess.io.output_dir.as_deref(), crate_name),
                         )
                     });
                 }
                 result
             })?;
 
+            drop(gctxt);
+
             if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
@@ -439,7 +411,7 @@ fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>)
 fn make_input(
     error_format: ErrorOutputType,
     free_matches: &[String],
-) -> Result<Option<(Input, Option<PathBuf>)>, ErrorGuaranteed> {
+) -> Result<Option<Input>, ErrorGuaranteed> {
     if free_matches.len() == 1 {
         let ifile = &free_matches[0];
         if ifile == "-" {
@@ -461,12 +433,12 @@ fn make_input(
                 let line = isize::from_str_radix(&line, 10)
                     .expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
                 let file_name = FileName::doc_test_source_code(PathBuf::from(path), line);
-                Ok(Some((Input::Str { name: file_name, input: src }, None)))
+                Ok(Some(Input::Str { name: file_name, input: src }))
             } else {
-                Ok(Some((Input::Str { name: FileName::anon_source_code(&src), input: src }, None)))
+                Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src }))
             }
         } else {
-            Ok(Some((Input::File(PathBuf::from(ifile)), Some(PathBuf::from(ifile)))))
+            Ok(Some(Input::File(PathBuf::from(ifile))))
         }
     } else {
         Ok(None)
@@ -560,7 +532,7 @@ fn show_content_with_pager(content: &str) {
 
 pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
     if sess.opts.unstable_opts.link_only {
-        if let Input::File(file) = compiler.input() {
+        if let Input::File(file) = &sess.io.input {
             // FIXME: #![crate_type] and #![crate_name] support not implemented yet
             sess.init_crate_types(collect_crate_types(sess, &[]));
             let outputs = compiler.build_output_filenames(sess, &[]);
@@ -601,13 +573,9 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp
     }
 }
 
-pub fn list_metadata(
-    sess: &Session,
-    metadata_loader: &dyn MetadataLoader,
-    input: &Input,
-) -> Compilation {
+pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Compilation {
     if sess.opts.unstable_opts.ls {
-        match *input {
+        match sess.io.input {
             Input::File(ref ifile) => {
                 let path = &(*ifile);
                 let mut v = Vec::new();
@@ -627,10 +595,7 @@ pub fn list_metadata(
 fn print_crate_info(
     codegen_backend: &dyn CodegenBackend,
     sess: &Session,
-    input: Option<&Input>,
-    odir: &Option<PathBuf>,
-    ofile: &Option<PathBuf>,
-    temps_dir: &Option<PathBuf>,
+    parse_attrs: bool,
 ) -> Compilation {
     use rustc_session::config::PrintRequest::*;
     // NativeStaticLibs and LinkArgs are special - printed during linking
@@ -639,18 +604,17 @@ fn print_crate_info(
         return Compilation::Continue;
     }
 
-    let attrs = match input {
-        None => None,
-        Some(input) => {
-            let result = parse_crate_attrs(sess, input);
-            match result {
-                Ok(attrs) => Some(attrs),
-                Err(mut parse_error) => {
-                    parse_error.emit();
-                    return Compilation::Stop;
-                }
+    let attrs = if parse_attrs {
+        let result = parse_crate_attrs(sess);
+        match result {
+            Ok(attrs) => Some(attrs),
+            Err(mut parse_error) => {
+                parse_error.emit();
+                return Compilation::Stop;
             }
         }
+    } else {
+        None
     };
     for req in &sess.opts.prints {
         match *req {
@@ -665,14 +629,9 @@ fn print_crate_info(
                 println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
             }
             FileNames | CrateName => {
-                let input = input.unwrap_or_else(|| {
-                    early_error(ErrorOutputType::default(), "no input file provided")
-                });
                 let attrs = attrs.as_ref().unwrap();
-                let t_outputs = rustc_interface::util::build_output_filenames(
-                    input, odir, ofile, temps_dir, attrs, sess,
-                );
-                let id = rustc_session::output::find_crate_name(sess, attrs, input);
+                let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess);
+                let id = rustc_session::output::find_crate_name(sess, attrs);
                 if *req == PrintRequest::CrateName {
                     println!("{id}");
                     continue;
@@ -1108,8 +1067,8 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     Some(matches)
 }
 
-fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::AttrVec> {
-    match input {
+fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> {
+    match &sess.io.input {
         Input::File(ifile) => rustc_parse::parse_crate_attrs_from_file(ifile, &sess.parse_sess),
         Input::Str { name, input } => rustc_parse::parse_crate_attrs_from_source_str(
             name.clone(),
index b2451bc730f79f7eb1ddea06cf54708d1dc24f52..446c6832cb7b607657a23a63e4c628d0123867cc 100644 (file)
@@ -9,14 +9,13 @@
 use rustc_middle::hir::map as hir_map;
 use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_session::config::{Input, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode};
+use rustc_session::config::{PpAstTreeMode, PpHirMode, PpMode, PpSourceMode};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
 use rustc_span::FileName;
 
 use std::cell::Cell;
 use std::fmt::Write;
-use std::path::Path;
 
 pub use self::PpMode::*;
 pub use self::PpSourceMode::*;
@@ -345,8 +344,8 @@ fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
     }
 }
 
-fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
-    let src_name = input.source_name();
+fn get_source(sess: &Session) -> (String, FileName) {
+    let src_name = sess.io.input.source_name();
     let src = String::clone(
         sess.source_map()
             .get_source_file(&src_name)
@@ -358,8 +357,8 @@ fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
     (src, src_name)
 }
 
-fn write_or_print(out: &str, ofile: Option<&Path>, sess: &Session) {
-    match ofile {
+fn write_or_print(out: &str, sess: &Session) {
+    match &sess.io.output_file {
         None => print!("{out}"),
         Some(p) => {
             if let Err(e) = std::fs::write(p, out) {
@@ -372,14 +371,8 @@ fn write_or_print(out: &str, ofile: Option<&Path>, sess: &Session) {
     }
 }
 
-pub fn print_after_parsing(
-    sess: &Session,
-    input: &Input,
-    krate: &ast::Crate,
-    ppm: PpMode,
-    ofile: Option<&Path>,
-) {
-    let (src, src_name) = get_source(input, sess);
+pub fn print_after_parsing(sess: &Session, krate: &ast::Crate, ppm: PpMode) {
+    let (src, src_name) = get_source(sess);
 
     let out = match ppm {
         Source(s) => {
@@ -407,22 +400,16 @@ pub fn print_after_parsing(
         _ => unreachable!(),
     };
 
-    write_or_print(&out, ofile, sess);
+    write_or_print(&out, sess);
 }
 
-pub fn print_after_hir_lowering<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    input: &Input,
-    krate: &ast::Crate,
-    ppm: PpMode,
-    ofile: Option<&Path>,
-) {
+pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) {
     if ppm.needs_analysis() {
-        abort_on_err(print_with_analysis(tcx, ppm, ofile), tcx.sess);
+        abort_on_err(print_with_analysis(tcx, ppm), tcx.sess);
         return;
     }
 
-    let (src, src_name) = get_source(input, tcx.sess);
+    let (src, src_name) = get_source(tcx.sess);
 
     let out = match ppm {
         Source(s) => {
@@ -433,7 +420,7 @@ pub fn print_after_hir_lowering<'tcx>(
                 let parse = &sess.parse_sess;
                 pprust::print_crate(
                     sess.source_map(),
-                    krate,
+                    &tcx.resolver_for_lowering(()).borrow().1,
                     src_name,
                     src,
                     annotation.pp_ann(),
@@ -446,7 +433,7 @@ pub fn print_after_hir_lowering<'tcx>(
 
         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| {
@@ -474,18 +461,14 @@ pub fn print_after_hir_lowering<'tcx>(
         _ => unreachable!(),
     };
 
-    write_or_print(&out, ofile, tcx.sess);
+    write_or_print(&out, tcx.sess);
 }
 
 // In an ideal world, this would be a public function called by the driver after
 // analysis is performed. However, we want to call `phase_3_run_analysis_passes`
 // with a different callback than the standard driver, so that isn't easy.
 // Instead, we call that function ourselves.
-fn print_with_analysis(
-    tcx: TyCtxt<'_>,
-    ppm: PpMode,
-    ofile: Option<&Path>,
-) -> Result<(), ErrorGuaranteed> {
+fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuaranteed> {
     tcx.analysis(())?;
     let out = match ppm {
         Mir => {
@@ -515,10 +498,25 @@ fn print_with_analysis(
             out
         }
 
+        ThirFlat => {
+            let mut out = String::new();
+            abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
+            debug!("pretty printing THIR flat");
+            for did in tcx.hir().body_owners() {
+                let _ = writeln!(
+                    out,
+                    "{:?}:\n{}\n",
+                    did,
+                    tcx.thir_flat(ty::WithOptConstParam::unknown(did))
+                );
+            }
+            out
+        }
+
         _ => unreachable!(),
     };
 
-    write_or_print(&out, ofile, tcx.sess);
+    write_or_print(&out, tcx.sess);
 
     Ok(())
 }
index 24258974bb97c67e05cabf9d649757f5d5d4ebf6..4ae372bb90432cc86908ed3f41dc6d0b64982806 100644 (file)
@@ -1,5 +1,5 @@
-// Error messages for EXXXX errors.  Each message should start and end with a
-// new line, and be wrapped to 80 characters.  In vim you can `:set tw=80` and
+// Error messages for EXXXX errors. Each message should start and end with a
+// new line, and be wrapped to 80 characters. In vim you can `:set tw=80` and
 // use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
 //
 // /!\ IMPORTANT /!\
 E0786: include_str!("./error_codes/E0786.md"),
 E0787: include_str!("./error_codes/E0787.md"),
 E0788: include_str!("./error_codes/E0788.md"),
+E0789: include_str!("./error_codes/E0789.md"),
 E0790: include_str!("./error_codes/E0790.md"),
 E0791: include_str!("./error_codes/E0791.md"),
+E0792: include_str!("./error_codes/E0792.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
 //  E0721, // `await` keyword
 //  E0723, // unstable feature in `const` context
 //  E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
-    E0789, // rustc_allowed_through_unstable_modules without stability attribute
 }
index 7edd93e56a945e4e9096efee47c07e9f14b1a410..1ae01106f2014c4362d29d3a4a306dde7f091bd0 100644 (file)
@@ -1 +1,46 @@
 #### This error code is internal to the compiler and will not be emitted with normal Rust code.
+#### Note: this error code is no longer emitted by the compiler.
+
+This error code shows the variance of a type's generic parameters.
+
+Erroneous code example:
+
+```compile_fail
+// NOTE: this feature is perma-unstable and should *only* be used for
+//       testing purposes.
+#![feature(rustc_attrs)]
+
+#[rustc_variance]
+struct Foo<'a, T> { // error: deliberate error to display type's variance
+    t: &'a mut T,
+}
+```
+
+which produces the following error:
+
+```text
+error: [-, o]
+ --> <anon>:4:1
+  |
+4 | struct Foo<'a, T> {
+  | ^^^^^^^^^^^^^^^^^
+```
+
+*Note that while `#[rustc_variance]` still exists and is used within the*
+*compiler, it no longer is marked as `E0208` and instead has no error code.*
+
+This error is deliberately triggered with the `#[rustc_variance]` attribute
+(`#![feature(rustc_attrs)]` must be enabled) and helps to show you the variance
+of the type's generic parameters. You can read more about variance and
+subtyping in [this section of the Rustnomicon]. For a more in depth look at
+variance (including a more complete list of common variances) see
+[this section of the Reference]. For information on how variance is implemented
+in the compiler, see [this section of `rustc-dev-guide`].
+
+This error can be easily fixed by removing the `#[rustc_variance]` attribute,
+the compiler's suggestion to comment it out can be applied automatically with
+`rustfix`.
+
+[this section of the Rustnomicon]: https://doc.rust-lang.org/nomicon/subtyping.html
+[this section of the Reference]: https://doc.rust-lang.org/reference/subtyping.html#variance
+[this section of `rustc-dev-guide`]: https://rustc-dev-guide.rust-lang.org/variance.html
index 38ad19bd6aa9a37c7b6030e2524a4975fd8402ed..1c62d410efe4799503ce55a0087140ed15a1ed59 100644 (file)
@@ -17,7 +17,7 @@ fn mutable() {
     foo(|| x = 2);
 }
 
-// Attempts to take a mutable reference to closed-over data.  Error message
+// Attempts to take a mutable reference to closed-over data. Error message
 // reads: `cannot borrow data mutably in a captured outer variable...`
 fn mut_addr() {
     let mut x = 0u32;
index ee9031dc3796c7a8189acc76dc2117337ed53b9d..d7998af85b94fc71c9c142abe46b9bbb9c4a06e6 100644 (file)
@@ -11,6 +11,6 @@ You cannot use `packed` and `align` hints on a same type. If you want to pack a
 type to a given size, you should provide a size to packed:
 
 ```
-#[repr(packed)] // ok!
+#[repr(packed(8))] // ok!
 struct Umbrella(i32);
 ```
index 9b1b77f3bc70652751f198928e76cc1dceff8686..a7b9bbeb122f70fcbc03c15dd4f33ad4b4d52ab2 100644 (file)
@@ -22,7 +22,7 @@ gets called when they go out of scope. This destructor gets exclusive
 access to the fields of the struct when it runs.
 
 This means that when `s` reaches the end of `demo`, its destructor
-gets exclusive access to its `&mut`-borrowed string data.  allowing
+gets exclusive access to its `&mut`-borrowed string data. allowing
 another borrow of that string data (`p`), to exist across the drop of
 `s` would be a violation of the principle that `&mut`-borrows have
 exclusive, unaliased access to their referenced data.
index 45d1cafa690624a0e49bf753cabfe4695d86e94d..b75735d602e053677ebcdc2efb7c6338a1d87910 100644 (file)
@@ -15,5 +15,5 @@ fn main() {}
 ```
 
 The items of marker traits cannot be overridden, so there's no need to have them
-when they cannot be changed per-type anyway.  If you wanted them for ergonomic
+when they cannot be changed per-type anyway. If you wanted them for ergonomic
 reasons, consider making an extension trait instead.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0789.md b/compiler/rustc_error_codes/src/error_codes/E0789.md
new file mode 100644 (file)
index 0000000..89b7cd4
--- /dev/null
@@ -0,0 +1,30 @@
+#### This error code is internal to the compiler and will not be emitted with normal Rust code.
+
+The internal `rustc_allowed_through_unstable_modules` attribute must be used
+on an item with a `stable` attribute.
+
+Erroneous code example:
+
+```compile_fail,E0789
+// NOTE: both of these attributes are perma-unstable and should *never* be
+//       used outside of the compiler and standard library.
+#![feature(rustc_attrs)]
+#![feature(staged_api)]
+
+#![unstable(feature = "foo_module", reason = "...", issue = "123")]
+
+#[rustc_allowed_through_unstable_modules]
+// #[stable(feature = "foo", since = "1.0")]
+struct Foo;
+// ^^^ error: `rustc_allowed_through_unstable_modules` attribute must be
+//            paired with a `stable` attribute
+```
+
+Typically when an item is marked with a `stable` attribute, the modules that
+enclose the item must also be marked with `stable` attributes, otherwise the
+item becomes *de facto* unstable. `#[rustc_allowed_through_unstable_modules]`
+is a workaround which allows an item to "escape" its unstable parent modules.
+This error occurs when an item is marked with
+`#[rustc_allowed_through_unstable_modules]` but no supplementary `stable`
+attribute exists. See [#99288](https://github.com/rust-lang/rust/pull/99288)
+for an example of `#[rustc_allowed_through_unstable_modules]` in use.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0792.md b/compiler/rustc_error_codes/src/error_codes/E0792.md
new file mode 100644 (file)
index 0000000..bad2b5a
--- /dev/null
@@ -0,0 +1,60 @@
+A type alias impl trait can only have its hidden type assigned
+when used fully generically (and within their defining scope).
+This means
+
+```compile_fail,E0792
+#![feature(type_alias_impl_trait)]
+
+type Foo<T> = impl std::fmt::Debug;
+
+fn foo() -> Foo<u32> {
+    5u32
+}
+```
+
+is not accepted. If it were accepted, one could create unsound situations like
+
+```compile_fail,E0792
+#![feature(type_alias_impl_trait)]
+
+type Foo<T> = impl Default;
+
+fn foo() -> Foo<u32> {
+    5u32
+}
+
+fn main() {
+    let x = Foo::<&'static mut String>::default();
+}
+```
+
+
+Instead you need to make the function generic:
+
+```
+#![feature(type_alias_impl_trait)]
+
+type Foo<T> = impl std::fmt::Debug;
+
+fn foo<U>() -> Foo<U> {
+    5u32
+}
+```
+
+This means that no matter the generic parameter to `foo`,
+the hidden type will always be `u32`.
+If you want to link the generic parameter to the hidden type,
+you can do that, too:
+
+
+```
+#![feature(type_alias_impl_trait)]
+
+use std::fmt::Debug;
+
+type Foo<T: Debug> = impl Debug;
+
+fn foo<U: Debug>() -> Foo<U> {
+    Vec::<U>::new()
+}
+```
index e5cd1142b20c8c8738055ac3d52d845fb801b24d..5f28839f136d6276fd3fb465dd749b8edb7d5ad2 100644 (file)
@@ -88,4 +88,5 @@ ast_passes_ty_alias_without_body =
 ast_passes_fn_without_body =
     free function without a body
     .suggestion = provide a definition for the function
-    .extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block
+
+ast_passes_extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block
index 2cd4733220e829ce4d68d0dc4bb3aee962277608..0021638c10268c9ce5fcf68c7ffac5d0793d570c 100644 (file)
@@ -120,3 +120,10 @@ borrowck_cannot_move_when_borrowed =
         [value] value
         *[other] {$value_place}
     } occurs here
+
+borrowck_opaque_type_non_generic_param =
+    expected generic {$kind} parameter, found `{$ty}`
+    .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 08ce5172574ac3bb1af28314ec2200a26b8d221a..6101b28ab0cdde9a42b69834de91ea4bff2d6198 100644 (file)
@@ -23,7 +23,7 @@ codegen_gcc_invalid_monomorphization_unsupported_element =
     invalid monomorphization of `{$name}` intrinsic: unsupported {$name} from `{$in_ty}` with element `{$elem_ty}` to `{$ret_ty}`
 
 codegen_gcc_invalid_monomorphization_invalid_bitmask =
-    invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
+    invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
 
 codegen_gcc_invalid_monomorphization_simd_shuffle =
     invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
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 c8c7afb5f919632b8555682136978d0ea4dc4c99..4924105128db6eb1d55afa46efdb612999b7fd5b 100644 (file)
@@ -179,9 +179,9 @@ codegen_ssa_extract_bundled_libs_write_file = failed to write file '{$rlib}': {$
 
 codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}`
 
-codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {error}
+codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error}
 
-codegen_ssa_read_file = failed to read file: {message}
+codegen_ssa_read_file = failed to read file: {$message}
 
 codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target
 
index ae0091b03736f3b6c78343ae5d7487ab7b12606a..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
@@ -193,7 +191,7 @@ infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis ->
 infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis ->
     [true] ...
     *[false] {""}
-}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`...
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
 infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis ->
     [true] ...
     *[false] {""}
@@ -209,7 +207,7 @@ infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis ->
 infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis ->
     [true] ...
     *[false] {""}
-}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{lifetime_1}`...
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`...
 infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis ->
     [true] ...
     *[false] {""}
@@ -225,7 +223,7 @@ infer_actual_impl_expl_expected_other_any = {$leading_ellipsis ->
 infer_actual_impl_expl_expected_other_some = {$leading_ellipsis ->
     [true] ...
     *[false] {""}
-}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`...
+}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
 infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis ->
     [true] ...
     *[false] {""}
@@ -268,28 +266,28 @@ infer_but_calling_introduces = {$has_param_name ->
     [true] `{$param_name}`
     *[false] `fn` parameter
 } has {$lifetime_kind ->
-    [named] lifetime `{lifetime}`
-    *[anon] an anonymous lifetime `'_`
-} but calling `{assoc_item}` introduces an implicit `'static` lifetime requirement
+    [true] lifetime `{$lifetime}`
+    *[false] an anonymous lifetime `'_`
+} but calling `{$assoc_item}` introduces an implicit `'static` lifetime requirement
     .label1 = {$has_lifetime ->
-        [named] lifetime `{lifetime}`
-        *[anon] an anonymous lifetime `'_`
+        [true] lifetime `{$lifetime}`
+        *[false] an anonymous lifetime `'_`
     }
     .label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path ->
-        [named] `impl` of `{$impl_path}`
-        *[anon] inherent `impl`
+        [true] `impl` of `{$impl_path}`
+        *[false] inherent `impl`
     }
 
 infer_but_needs_to_satisfy = {$has_param_name ->
     [true] `{$param_name}`
     *[false] `fn` parameter
 } has {$has_lifetime ->
-    [named] lifetime `{lifetime}`
-    *[anon] an anonymous lifetime `'_`
+    [true] lifetime `{$lifetime}`
+    *[false] an anonymous lifetime `'_`
 } but it needs to satisfy a `'static` lifetime requirement
     .influencer = this data with {$has_lifetime ->
-        [named] lifetime `{lifetime}`
-        *[anon] an anonymous lifetime `'_`
+        [true] lifetime `{$lifetime}`
+        *[false] an anonymous lifetime `'_`
     }...
     .require = {$spans_empty ->
         *[true] ...is used and required to live as long as `'static` here
@@ -302,8 +300,8 @@ infer_more_targeted = {$has_param_name ->
     [true] `{$param_name}`
     *[false] `fn` parameter
 } has {$has_lifetime ->
-    [named] lifetime `{lifetime}`
-    *[anon] an anonymous lifetime `'_`
+    [true] lifetime `{$lifetime}`
+    *[false] an anonymous lifetime `'_`
 } but calling `{$ident}` introduces an implicit `'static` lifetime requirement
 
 infer_ril_introduced_here = `'static` requirement introduced here
index d63ff77d8e2558bd5decf85363d07b90258c6bef..dca678dff7a793253524fe055db88b49934f9dc1 100644 (file)
@@ -100,6 +100,8 @@ lint_cstring_ptr = getting the inner pointer of a temporary `CString`
     .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
     .help = for more information, see https://doc.rust-lang.org/reference/destructors.html
 
+lint_multple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits
+
 lint_identifier_non_ascii_char = identifier contains non-ASCII characters
 
 lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints
index a082c0b61fa7ed293b873b9e054f7f9e1481957e..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
 
@@ -364,3 +372,5 @@ mir_build_suggest_let_else = you might want to use `let else` to handle the {$co
         [one] variant that isn't
         *[other] variants that aren't
     } matched
+
+mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
index 8f063f5082c9541c249b722fc2f9090ad4046d7b..1728ef70cba0a7bd817b4db0a917b9060587c9db 100644 (file)
@@ -199,6 +199,17 @@ parse_match_arm_body_without_braces = `match` arm body without braces
         } with a body
     .suggestion_use_comma_not_semicolon = use a comma to end a `match` arm expression
 
+parse_inclusive_range_extra_equals = unexpected `=` after inclusive range
+    .suggestion_remove_eq = use `..=` instead
+    .note = inclusive ranges end with a single equals sign (`..=`)
+
+parse_inclusive_range_match_arrow = unexpected `=>` after open range
+    .suggestion_add_space = add a space between the pattern and `=>`
+
+parse_inclusive_range_no_end = inclusive range with no end
+    .suggestion_open_range = use `..` instead
+    .note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
 parse_struct_literal_not_allowed_here = struct literals are not allowed here
     .suggestion = surround the struct literal with parentheses
 
@@ -238,6 +249,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 1040ee1c97d814b8a04c97bcb2a88fcfa68c30c6..abe65a0e3fef06415599478dad5d702316a7a6df 100644 (file)
@@ -10,17 +10,17 @@ ty_utils_address_and_deref_not_supported = dereferencing or taking the address i
 
 ty_utils_array_not_supported = array construction is not supported in generic constants
 
-ty_utils_block_not_supported = blocks are not supported in generic constant
+ty_utils_block_not_supported = blocks are not supported in generic constants
 
-ty_utils_never_to_any_not_supported = converting nevers to any is not supported in generic constant
+ty_utils_never_to_any_not_supported = converting nevers to any is not supported in generic constants
 
 ty_utils_tuple_not_supported = tuple construction is not supported in generic constants
 
-ty_utils_index_not_supported = indexing is not supported in generic constant
+ty_utils_index_not_supported = indexing is not supported in generic constants
 
-ty_utils_field_not_supported = field access is not supported in generic constant
+ty_utils_field_not_supported = field access is not supported in generic constants
 
-ty_utils_const_block_not_supported = const blocks are not supported in generic constant
+ty_utils_const_block_not_supported = const blocks are not supported in generic constants
 
 ty_utils_adt_not_supported = struct/enum construction is not supported in generic constants
 
@@ -44,4 +44,4 @@ ty_utils_control_flow_not_supported = control flow is not supported in generic c
 
 ty_utils_inline_asm_not_supported = assembly is not supported in generic constants
 
-ty_utils_operation_not_supported = unsupported operation in generic constant
+ty_utils_operation_not_supported = unsupported operation in generic constants
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 e19a6fe0ee9bff2d5a0a5c28a7ace6c976c2fa9a..4ad24c1400d69d1a5ec36650443b4ab4b00a0e88 100644 (file)
@@ -114,9 +114,9 @@ pub struct Diagnostic {
     pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
     args: FxHashMap<DiagnosticArgName<'static>, DiagnosticArgValue<'static>>,
 
-    /// This is not used for highlighting or rendering any error message.  Rather, it can be used
-    /// as a sort key to sort a buffer of diagnostics.  By default, it is the primary span of
-    /// `span` if there is one.  Otherwise, it is `DUMMY_SP`.
+    /// This is not used for highlighting or rendering any error message. Rather, it can be used
+    /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
+    /// `span` if there is one. Otherwise, it is `DUMMY_SP`.
     pub sort_span: Span,
 
     /// If diagnostic is from Lint, custom hash function ignores notes
@@ -629,19 +629,27 @@ pub fn multipart_suggestion_with_style(
         applicability: Applicability,
         style: SuggestionStyle,
     ) -> &mut Self {
-        assert!(!suggestion.is_empty());
-        debug_assert!(
-            !(suggestion.iter().any(|(sp, text)| sp.is_empty() && text.is_empty())),
-            "Span must not be empty and have no suggestion"
+        let mut parts = suggestion
+            .into_iter()
+            .map(|(span, snippet)| SubstitutionPart { snippet, span })
+            .collect::<Vec<_>>();
+
+        parts.sort_unstable_by_key(|part| part.span);
+
+        assert!(!parts.is_empty());
+        debug_assert_eq!(
+            parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
+            None,
+            "Span must not be empty and have no suggestion",
+        );
+        debug_assert_eq!(
+            parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
+            None,
+            "suggestion must not have overlapping parts",
         );
 
         self.push_suggestion(CodeSuggestion {
-            substitutions: vec![Substitution {
-                parts: suggestion
-                    .into_iter()
-                    .map(|(span, snippet)| SubstitutionPart { snippet, span })
-                    .collect(),
-            }],
+            substitutions: vec![Substitution { parts }],
             msg: self.subdiagnostic_message_to_diagnostic_message(msg),
             style,
             applicability,
@@ -802,25 +810,34 @@ pub fn multipart_suggestions(
         suggestions: impl IntoIterator<Item = Vec<(Span, String)>>,
         applicability: Applicability,
     ) -> &mut Self {
-        let suggestions: Vec<_> = suggestions.into_iter().collect();
-        debug_assert!(
-            !(suggestions
-                .iter()
-                .flatten()
-                .any(|(sp, suggestion)| sp.is_empty() && suggestion.is_empty())),
-            "Span must not be empty and have no suggestion"
-        );
+        let substitutions = suggestions
+            .into_iter()
+            .map(|sugg| {
+                let mut parts = sugg
+                    .into_iter()
+                    .map(|(span, snippet)| SubstitutionPart { snippet, span })
+                    .collect::<Vec<_>>();
+
+                parts.sort_unstable_by_key(|part| part.span);
+
+                assert!(!parts.is_empty());
+                debug_assert_eq!(
+                    parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
+                    None,
+                    "Span must not be empty and have no suggestion",
+                );
+                debug_assert_eq!(
+                    parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
+                    None,
+                    "suggestion must not have overlapping parts",
+                );
+
+                Substitution { parts }
+            })
+            .collect();
 
         self.push_suggestion(CodeSuggestion {
-            substitutions: suggestions
-                .into_iter()
-                .map(|sugg| Substitution {
-                    parts: sugg
-                        .into_iter()
-                        .map(|(span, snippet)| SubstitutionPart { snippet, span })
-                        .collect(),
-                })
-                .collect(),
+            substitutions,
             msg: self.subdiagnostic_message_to_diagnostic_message(msg),
             style: SuggestionStyle::ShowCode,
             applicability,
index 7f01df321010bd39682d7378b980e6ea29a0e285..628e199992152937392392452603f05f8662ff62 100644 (file)
@@ -1791,7 +1791,7 @@ fn emit_suggestion_default(
 
             if let Some(span) = span.primary_span() {
                 // Compare the primary span of the diagnostic with the span of the suggestion
-                // being emitted.  If they belong to the same file, we don't *need* to show the
+                // being emitted. If they belong to the same file, we don't *need* to show the
                 // file name, saving in verbosity, but if it *isn't* we do need it, otherwise we're
                 // telling users to make a change but not clarifying *where*.
                 let loc = sm.lookup_char_pos(parts[0].span.lo());
@@ -2529,11 +2529,11 @@ fn emit_to_destination(
     //
     // On Unix systems, we write into a buffered terminal rather than directly to a terminal. When
     // the .flush() is called we take the buffer created from the buffered writes and write it at
-    // one shot.  Because the Unix systems use ANSI for the colors, which is a text-based styling
+    // one shot. Because the Unix systems use ANSI for the colors, which is a text-based styling
     // scheme, this buffered approach works and maintains the styling.
     //
     // On Windows, styling happens through calls to a terminal API. This prevents us from using the
-    // same buffering approach.  Instead, we use a global Windows mutex, which we acquire long
+    // same buffering approach. Instead, we use a global Windows mutex, which we acquire long
     // enough to output the full error message, then we release.
     let _buffer_lock = lock::acquire_global_lock("rustc_errors");
     for (pos, line) in rendered_buffer.iter().enumerate() {
index 535812fb0e228f7e413c219293395bdbde4ad7f7..d076fc08b0e2f1f023e73a3259d18c6cf9d98795 100644 (file)
@@ -3,6 +3,7 @@
 //! This module contains the code for creating and emitting diagnostics.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(array_windows)]
 #![feature(drain_filter)]
 #![feature(if_let_guard)]
 #![feature(is_terminal)]
index ffde8480c02117283c3ac7c47d96f4c48dcabe58..951d59246785d08bff71641690fe154308428a34 100644 (file)
@@ -63,21 +63,21 @@ pub enum Annotatable {
 
 impl Annotatable {
     pub fn span(&self) -> Span {
-        match *self {
-            Annotatable::Item(ref item) => item.span,
-            Annotatable::TraitItem(ref trait_item) => trait_item.span,
-            Annotatable::ImplItem(ref impl_item) => impl_item.span,
-            Annotatable::ForeignItem(ref foreign_item) => foreign_item.span,
-            Annotatable::Stmt(ref stmt) => stmt.span,
-            Annotatable::Expr(ref expr) => expr.span,
-            Annotatable::Arm(ref arm) => arm.span,
-            Annotatable::ExprField(ref field) => field.span,
-            Annotatable::PatField(ref fp) => fp.pat.span,
-            Annotatable::GenericParam(ref gp) => gp.ident.span,
-            Annotatable::Param(ref p) => p.span,
-            Annotatable::FieldDef(ref sf) => sf.span,
-            Annotatable::Variant(ref v) => v.span,
-            Annotatable::Crate(ref c) => c.spans.inner_span,
+        match self {
+            Annotatable::Item(item) => item.span,
+            Annotatable::TraitItem(trait_item) => trait_item.span,
+            Annotatable::ImplItem(impl_item) => impl_item.span,
+            Annotatable::ForeignItem(foreign_item) => foreign_item.span,
+            Annotatable::Stmt(stmt) => stmt.span,
+            Annotatable::Expr(expr) => expr.span,
+            Annotatable::Arm(arm) => arm.span,
+            Annotatable::ExprField(field) => field.span,
+            Annotatable::PatField(fp) => fp.pat.span,
+            Annotatable::GenericParam(gp) => gp.ident.span,
+            Annotatable::Param(p) => p.span,
+            Annotatable::FieldDef(sf) => sf.span,
+            Annotatable::Variant(v) => v.span,
+            Annotatable::Crate(c) => c.spans.inner_span,
         }
     }
 
index f4c6f3386ade23ce244e629ce715ce72a37d83e7..1fcbdfd9be5ce14353b7f1c572e2af7d6333f42b 100644 (file)
@@ -298,7 +298,7 @@ fn can_skip(stream: &AttrTokenStream) -> bool {
                     Some(AttrTokenTree::Delimited(sp, delim, inner))
                         .into_iter()
                 }
-                AttrTokenTree::Token(ref token, _) if let TokenKind::Interpolated(ref nt) = token.kind => {
+                AttrTokenTree::Token(ref token, _) if let TokenKind::Interpolated(nt) = &token.kind => {
                     panic!(
                         "Nonterminal should have been flattened at {:?}: {:?}",
                         token.span, nt
index 5d47c1ed363fbf0463ddde0118bba718d9ca10ec..79d058d9c97360d0aec61b0128d8ad140e14593d 100644 (file)
@@ -144,12 +144,12 @@ pub fn mut_visit_with<F: MutVisitor>(&mut self, vis: &mut F) {
             }
 
             pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
-                match *self {
-                    AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
+                match self {
+                    AstFragment::OptExpr(Some(expr)) => visitor.visit_expr(expr),
                     AstFragment::OptExpr(None) => {}
-                    AstFragment::MethodReceiverExpr(ref expr) => visitor.visit_method_receiver_expr(expr),
-                    $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)*
-                    $($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] {
+                    AstFragment::MethodReceiverExpr(expr) => visitor.visit_method_receiver_expr(expr),
+                    $($(AstFragment::$Kind(ast) => visitor.$visit_ast(ast),)?)*
+                    $($(AstFragment::$Kind(ast) => for ast_elt in &ast[..] {
                         visitor.$visit_ast_elt(ast_elt, $($args)*);
                     })?)*
                 }
@@ -592,7 +592,7 @@ fn collect_invocations(
                     let expn_id = invoc.expansion_data.id;
                     let parent_def = self.cx.resolver.invocation_parent(expn_id);
                     let span = match &mut invoc.kind {
-                        InvocationKind::Bang { ref mut span, .. } => span,
+                        InvocationKind::Bang { span, .. } => span,
                         InvocationKind::Attr { attr, .. } => &mut attr.span,
                         InvocationKind::Derive { path, .. } => &mut path.span,
                     };
@@ -945,8 +945,8 @@ pub fn ensure_complete_parse<'a>(
         let def_site_span = parser.token.span.with_ctxt(SyntaxContext::root());
 
         let semi_span = parser.sess.source_map().next_point(span);
-        let add_semicolon = match parser.sess.source_map().span_to_snippet(semi_span) {
-            Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => {
+        let add_semicolon = match &parser.sess.source_map().span_to_snippet(semi_span) {
+            Ok(snippet) if &snippet[..] != ";" && kind_name == "expression" => {
                 Some(span.shrink_to_hi())
             }
             _ => None,
index 0b8847f827df1aa6ad9b8a056ccadba7d03ed9aa..5be134f4e664c80c189cefab7d41baa380b41045 100644 (file)
@@ -151,9 +151,9 @@ impl<'a, T> Iterator for &'a Stack<'a, T> {
 
     // Iterates from top to bottom of the stack.
     fn next(&mut self) -> Option<&'a T> {
-        match *self {
+        match self {
             Stack::Empty => None,
-            Stack::Push { ref top, ref prev } => {
+            Stack::Push { top, prev } => {
                 *self = prev;
                 Some(top)
             }
@@ -437,8 +437,8 @@ fn check_nested_occurrences(
                 // We check that the meta-variable is correctly used.
                 check_occurrences(sess, node_id, tt, macros, binders, ops, valid);
             }
-            (NestedMacroState::MacroRulesNotName, &TokenTree::Delimited(_, ref del))
-            | (NestedMacroState::MacroName, &TokenTree::Delimited(_, ref del))
+            (NestedMacroState::MacroRulesNotName, TokenTree::Delimited(_, del))
+            | (NestedMacroState::MacroName, TokenTree::Delimited(_, del))
                 if del.delim == Delimiter::Brace =>
             {
                 let macro_rules = state == NestedMacroState::MacroRulesNotName;
@@ -497,7 +497,7 @@ fn check_nested_occurrences(
                     valid,
                 );
             }
-            (_, ref tt) => {
+            (_, tt) => {
                 state = NestedMacroState::Empty;
                 check_occurrences(sess, node_id, tt, macros, binders, ops, valid);
             }
index c0489f686336b2747c9252500425e451561a83b6..cd431f5701958e529531504fc9f9574915b7cf4b 100644 (file)
@@ -10,7 +10,7 @@
 
 use rustc_ast as ast;
 use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind, TokenKind::*};
-use rustc_ast::tokenstream::{DelimSpan, TokenStream};
+use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
 use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, TransparencyError};
@@ -212,7 +212,6 @@ fn expand_macro<'cx>(
             };
             let arm_span = rhses[i].span();
 
-            let rhs_spans = rhs.tts.iter().map(|t| t.span()).collect::<Vec<_>>();
             // rhs has holes ( `$id` and `$(...)` that need filled)
             let mut tts = match transcribe(cx, &named_matches, &rhs, rhs_span, transparency) {
                 Ok(tts) => tts,
@@ -224,12 +223,25 @@ fn expand_macro<'cx>(
 
             // Replace all the tokens for the corresponding positions in the macro, to maintain
             // proper positions in error reporting, while maintaining the macro_backtrace.
-            if rhs_spans.len() == tts.len() {
+            if tts.len() == rhs.tts.len() {
                 tts = tts.map_enumerated(|i, tt| {
                     let mut tt = tt.clone();
-                    let mut sp = rhs_spans[i];
-                    sp = sp.with_ctxt(tt.span().ctxt());
-                    tt.set_span(sp);
+                    let rhs_tt = &rhs.tts[i];
+                    let ctxt = tt.span().ctxt();
+                    match (&mut tt, rhs_tt) {
+                        // preserve the delim spans if able
+                        (
+                            TokenTree::Delimited(target_sp, ..),
+                            mbe::TokenTree::Delimited(source_sp, ..),
+                        ) => {
+                            target_sp.open = source_sp.open.with_ctxt(ctxt);
+                            target_sp.close = source_sp.close.with_ctxt(ctxt);
+                        }
+                        _ => {
+                            let sp = rhs_tt.span().with_ctxt(ctxt);
+                            tt.set_span(sp);
+                        }
+                    }
                     tt
                 });
             }
@@ -486,11 +498,11 @@ pub fn compile_declarative_macro(
     let mut valid = true;
 
     // Extract the arguments:
-    let lhses = match argument_map[&MacroRulesNormalizedIdent::new(lhs_nm)] {
-        MatchedSeq(ref s) => s
+    let lhses = match &argument_map[&MacroRulesNormalizedIdent::new(lhs_nm)] {
+        MatchedSeq(s) => s
             .iter()
             .map(|m| {
-                if let MatchedTokenTree(ref tt) = *m {
+                if let MatchedTokenTree(tt) = m {
                     let tt = mbe::quoted::parse(
                         TokenStream::new(vec![tt.clone()]),
                         true,
@@ -510,11 +522,11 @@ pub fn compile_declarative_macro(
         _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"),
     };
 
-    let rhses = match argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] {
-        MatchedSeq(ref s) => s
+    let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] {
+        MatchedSeq(s) => s
             .iter()
             .map(|m| {
-                if let MatchedTokenTree(ref tt) = *m {
+                if let MatchedTokenTree(tt) = m {
                     return mbe::quoted::parse(
                         TokenStream::new(vec![tt.clone()]),
                         false,
@@ -624,21 +636,21 @@ fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree)
 fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
     use mbe::TokenTree;
     for tt in tts {
-        match *tt {
+        match tt {
             TokenTree::Token(..)
             | TokenTree::MetaVar(..)
             | TokenTree::MetaVarDecl(..)
             | TokenTree::MetaVarExpr(..) => (),
-            TokenTree::Delimited(_, ref del) => {
+            TokenTree::Delimited(_, del) => {
                 if !check_lhs_no_empty_seq(sess, &del.tts) {
                     return false;
                 }
             }
-            TokenTree::Sequence(span, ref seq) => {
+            TokenTree::Sequence(span, seq) => {
                 if seq.separator.is_none()
-                    && seq.tts.iter().all(|seq_tt| match *seq_tt {
+                    && seq.tts.iter().all(|seq_tt| match seq_tt {
                         TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true,
-                        TokenTree::Sequence(_, ref sub_seq) => {
+                        TokenTree::Sequence(_, sub_seq) => {
                             sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
                                 || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne
                         }
@@ -736,21 +748,21 @@ fn new(tts: &'tt [mbe::TokenTree]) -> FirstSets<'tt> {
         fn build_recur<'tt>(sets: &mut FirstSets<'tt>, tts: &'tt [TokenTree]) -> TokenSet<'tt> {
             let mut first = TokenSet::empty();
             for tt in tts.iter().rev() {
-                match *tt {
+                match tt {
                     TokenTree::Token(..)
                     | TokenTree::MetaVar(..)
                     | TokenTree::MetaVarDecl(..)
                     | TokenTree::MetaVarExpr(..) => {
                         first.replace_with(TtHandle::TtRef(tt));
                     }
-                    TokenTree::Delimited(span, ref delimited) => {
+                    TokenTree::Delimited(span, delimited) => {
                         build_recur(sets, &delimited.tts);
                         first.replace_with(TtHandle::from_token_kind(
                             token::OpenDelim(delimited.delim),
                             span.open,
                         ));
                     }
-                    TokenTree::Sequence(sp, ref seq_rep) => {
+                    TokenTree::Sequence(sp, seq_rep) => {
                         let subfirst = build_recur(sets, &seq_rep.tts);
 
                         match sets.first.entry(sp.entire()) {
@@ -804,7 +816,7 @@ fn first(&self, tts: &'tt [mbe::TokenTree]) -> TokenSet<'tt> {
         let mut first = TokenSet::empty();
         for tt in tts.iter() {
             assert!(first.maybe_empty);
-            match *tt {
+            match tt {
                 TokenTree::Token(..)
                 | TokenTree::MetaVar(..)
                 | TokenTree::MetaVarDecl(..)
@@ -812,14 +824,14 @@ fn first(&self, tts: &'tt [mbe::TokenTree]) -> TokenSet<'tt> {
                     first.add_one(TtHandle::TtRef(tt));
                     return first;
                 }
-                TokenTree::Delimited(span, ref delimited) => {
+                TokenTree::Delimited(span, delimited) => {
                     first.add_one(TtHandle::from_token_kind(
                         token::OpenDelim(delimited.delim),
                         span.open,
                     ));
                     return first;
                 }
-                TokenTree::Sequence(sp, ref seq_rep) => {
+                TokenTree::Sequence(sp, seq_rep) => {
                     let subfirst_owned;
                     let subfirst = match self.first.get(&sp.entire()) {
                         Some(Some(subfirst)) => subfirst,
@@ -1041,7 +1053,7 @@ fn check_matcher_core<'tt>(
 
         // First, update `last` so that it corresponds to the set
         // of NT tokens that might end the sequence `... token`.
-        match *token {
+        match token {
             TokenTree::Token(..)
             | TokenTree::MetaVar(..)
             | TokenTree::MetaVarDecl(..)
@@ -1057,7 +1069,7 @@ fn check_matcher_core<'tt>(
                     suffix_first = build_suffix_first();
                 }
             }
-            TokenTree::Delimited(span, ref d) => {
+            TokenTree::Delimited(span, d) => {
                 let my_suffix = TokenSet::singleton(TtHandle::from_token_kind(
                     token::CloseDelim(d.delim),
                     span.close,
@@ -1070,7 +1082,7 @@ fn check_matcher_core<'tt>(
                 // against SUFFIX
                 continue 'each_token;
             }
-            TokenTree::Sequence(_, ref seq_rep) => {
+            TokenTree::Sequence(_, seq_rep) => {
                 suffix_first = build_suffix_first();
                 // The trick here: when we check the interior, we want
                 // to include the separator (if any) as a potential
@@ -1372,8 +1384,8 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
 }
 
 fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
-    match *tt {
-        mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token).into(),
+    match tt {
+        mbe::TokenTree::Token(token) => pprust::token_to_string(&token).into(),
         mbe::TokenTree::MetaVar(_, name) => format!("${}", name),
         mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind),
         mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name),
index 878284f5928de6cc4fffbe77a8bf94f4a20b3891..bc298b0ad2b1e37f8d78faa0d3433edbe7bea88a 100644 (file)
@@ -171,7 +171,7 @@ fn parse_tree(
                     } else {
                         match delim {
                             Delimiter::Brace => {
-                                // The delimiter is `{`.  This indicates the beginning
+                                // The delimiter is `{`. This indicates the beginning
                                 // of a meta-variable expression (e.g. `${count(ident)}`).
                                 // Try to parse the meta-variable expression.
                                 match MetaVarExpr::parse(&tts, delim_span.entire(), sess) {
@@ -200,7 +200,7 @@ fn parse_tree(
                         }
                     }
                     // If we didn't find a metavar expression above, then we must have a
-                    // repetition sequence in the macro (e.g. `$(pat)*`).  Parse the
+                    // repetition sequence in the macro (e.g. `$(pat)*`). Parse the
                     // contents of the sequence itself
                     let sequence = parse(tts, parsing_patterns, sess, node_id, features, edition);
                     // Get the Kleene operator and optional separator
index bec6d1a2df7d873301f1d9ebe3568fb8143f574e..b79835be73a7ec1dfd04438ea4257c8cc326bda7 100644 (file)
@@ -47,8 +47,7 @@ impl<'a> Iterator for Frame<'a> {
 
     fn next(&mut self) -> Option<&'a mbe::TokenTree> {
         match self {
-            Frame::Delimited { tts, ref mut idx, .. }
-            | Frame::Sequence { tts, ref mut idx, .. } => {
+            Frame::Delimited { tts, idx, .. } | Frame::Sequence { tts, idx, .. } => {
                 let res = tts.get(*idx);
                 *idx += 1;
                 res
@@ -220,13 +219,13 @@ pub(super) fn transcribe<'a>(
                 let ident = MacroRulesNormalizedIdent::new(original_ident);
                 if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
                     match cur_matched {
-                        MatchedTokenTree(ref tt) => {
+                        MatchedTokenTree(tt) => {
                             // `tt`s are emitted into the output stream directly as "raw tokens",
                             // without wrapping them into groups.
                             let token = tt.clone();
                             result.push(token);
                         }
-                        MatchedNonterminal(ref nt) => {
+                        MatchedNonterminal(nt) => {
                             // Other variables are emitted into the output stream as groups with
                             // `Delimiter::Invisible` to maintain parsing priorities.
                             // `Interpolated` is currently used for such groups in rustc parser.
@@ -299,12 +298,11 @@ fn lookup_cur_matched<'a>(
     interpolations: &'a FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
     repeats: &[(usize, usize)],
 ) -> Option<&'a NamedMatch> {
-    interpolations.get(&ident).map(|matched| {
-        let mut matched = matched;
+    interpolations.get(&ident).map(|mut matched| {
         for &(idx, _) in repeats {
             match matched {
                 MatchedTokenTree(_) | MatchedNonterminal(_) => break,
-                MatchedSeq(ref ads) => matched = ads.get(idx).unwrap(),
+                MatchedSeq(ads) => matched = ads.get(idx).unwrap(),
             }
         }
 
@@ -339,7 +337,7 @@ fn with(self, other: LockstepIterSize) -> LockstepIterSize {
         match self {
             LockstepIterSize::Unconstrained => other,
             LockstepIterSize::Contradiction(_) => self,
-            LockstepIterSize::Constraint(l_len, ref l_id) => match other {
+            LockstepIterSize::Constraint(l_len, l_id) => match other {
                 LockstepIterSize::Unconstrained => self,
                 LockstepIterSize::Contradiction(_) => other,
                 LockstepIterSize::Constraint(r_len, _) if l_len == r_len => self,
@@ -378,33 +376,33 @@ fn lockstep_iter_size(
     repeats: &[(usize, usize)],
 ) -> LockstepIterSize {
     use mbe::TokenTree;
-    match *tree {
-        TokenTree::Delimited(_, ref delimited) => {
+    match tree {
+        TokenTree::Delimited(_, delimited) => {
             delimited.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
                 size.with(lockstep_iter_size(tt, interpolations, repeats))
             })
         }
-        TokenTree::Sequence(_, ref seq) => {
+        TokenTree::Sequence(_, seq) => {
             seq.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
                 size.with(lockstep_iter_size(tt, interpolations, repeats))
             })
         }
         TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => {
-            let name = MacroRulesNormalizedIdent::new(name);
+            let name = MacroRulesNormalizedIdent::new(*name);
             match lookup_cur_matched(name, interpolations, repeats) {
                 Some(matched) => match matched {
                     MatchedTokenTree(_) | MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
-                    MatchedSeq(ref ads) => LockstepIterSize::Constraint(ads.len(), name),
+                    MatchedSeq(ads) => LockstepIterSize::Constraint(ads.len(), name),
                 },
                 _ => LockstepIterSize::Unconstrained,
             }
         }
-        TokenTree::MetaVarExpr(_, ref expr) => {
+        TokenTree::MetaVarExpr(_, expr) => {
             let default_rslt = LockstepIterSize::Unconstrained;
             let Some(ident) = expr.ident() else { return default_rslt; };
             let name = MacroRulesNormalizedIdent::new(ident);
             match lookup_cur_matched(name, interpolations, repeats) {
-                Some(MatchedSeq(ref ads)) => {
+                Some(MatchedSeq(ads)) => {
                     default_rslt.with(LockstepIterSize::Constraint(ads.len(), name))
                 }
                 _ => default_rslt,
@@ -449,7 +447,7 @@ fn count<'a>(
                     Some(_) => Err(out_of_bounds_err(cx, declared_lhs_depth, sp.entire(), "count")),
                 }
             }
-            MatchedSeq(ref named_matches) => {
+            MatchedSeq(named_matches) => {
                 let new_declared_lhs_depth = declared_lhs_depth + 1;
                 match depth_opt {
                     None => named_matches
@@ -472,7 +470,7 @@ fn count<'a>(
     // before we start counting. `matched` contains the various levels of the
     // tree as we descend, and its final value is the subtree we are currently at.
     for &(idx, _) in repeats {
-        if let MatchedSeq(ref ads) = matched {
+        if let MatchedSeq(ads) = matched {
             matched = &ads[idx];
         }
     }
index e49f112bf20a69a2ec01c6d29f346ae9504d3d47..0726d922c84a3e494ccbec353c20e6df333ccd73 100644 (file)
@@ -176,9 +176,9 @@ struct PatIdentVisitor {
     }
     impl<'a> visit::Visitor<'a> for PatIdentVisitor {
         fn visit_pat(&mut self, p: &'a ast::Pat) {
-            match p.kind {
-                PatKind::Ident(_, ref ident, _) => {
-                    self.spans.push(ident.span.clone());
+            match &p.kind {
+                PatKind::Ident(_, ident, _) => {
+                    self.spans.push(ident.span);
                 }
                 _ => {
                     visit::walk_pat(self, p);
@@ -290,10 +290,8 @@ fn parse_expr_from_source_str(
         )
         .unwrap();
 
-        let tts: Vec<_> = match expr.kind {
-            ast::ExprKind::MacCall(ref mac) => mac.args.tokens.clone().into_trees().collect(),
-            _ => panic!("not a macro"),
-        };
+        let ast::ExprKind::MacCall(mac) = &expr.kind else { panic!("not a macro") };
+        let tts: Vec<_> = mac.args.tokens.clone().into_trees().collect();
 
         let span = tts.iter().rev().next().unwrap().span();
 
@@ -318,11 +316,8 @@ fn out_of_line_mod() {
         .unwrap()
         .unwrap();
 
-        if let ast::ItemKind::Mod(_, ref mod_kind) = item.kind {
-            assert!(matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2));
-        } else {
-            panic!();
-        }
+        let ast::ItemKind::Mod(_, mod_kind) = &item.kind else { panic!() };
+        assert!(matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2));
     });
 }
 
index 768bdab8a54199a10aec996bc8c9a6bfa897f17c..341ae18541b3796a5c58c2a89cfe9c1051fc181b 100644 (file)
@@ -230,7 +230,7 @@ fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self {
                     let stream = TokenStream::from_nonterminal_ast(&nt);
                     // A hack used to pass AST fragments to attribute and derive
                     // macros as a single nonterminal token instead of a token
-                    // stream.  Such token needs to be "unwrapped" and not
+                    // stream. Such token needs to be "unwrapped" and not
                     // represented as a delimited group.
                     // FIXME: It needs to be removed, but there are some
                     // compatibility issues (see #73345).
@@ -597,8 +597,8 @@ fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
     }
 
     fn path(&mut self, file: &Self::SourceFile) -> String {
-        match file.name {
-            FileName::Real(ref name) => name
+        match &file.name {
+            FileName::Real(name) => name
                 .local_path()
                 .expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`")
                 .to_str()
index 196c31302a0d2a91d9c59aa153cb7e3d78ea2b5f..af9c40a3ba5227b249221b6a1e59a5fdfe1a2c0a 100644 (file)
@@ -160,6 +160,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, intrinsics, "1.0.0", None, None),
     /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
     (active, lang_items, "1.0.0", None, None),
+    /// Allows the `multiple_supertrait_upcastable` lint.
+    (active, multiple_supertrait_upcastable, "CURRENT_RUSTC_VERSION", None, None),
     /// Allows using `#[omit_gdb_pretty_printer_section]`.
     (active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
     /// Allows using `#[prelude_import]` on glob `use` items.
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 921039797869feca60ee20aee3677e578998b757..cca5ead0f83951c19594d3704afb0264164245c6 100644 (file)
@@ -751,7 +751,7 @@ pub enum LifetimeRes {
         binder: NodeId,
     },
     /// This variant is used for anonymous lifetimes that we did not resolve during
-    /// late resolution.  Those lifetimes will be inferred by typechecking.
+    /// late resolution. Those lifetimes will be inferred by typechecking.
     Infer,
     /// Explicit `'static` lifetime.
     Static,
index 60f5b79de1033d13eb4fcfb56ba78324709eaddd..4696a4bd9ab63aeab10c4291c451fc93d1eddce4 100644 (file)
@@ -94,7 +94,7 @@ pub enum LifetimeName {
     /// Implicit lifetime in a context like `dyn Foo`. This is
     /// distinguished from implicit lifetimes elsewhere because the
     /// lifetime that they default to must appear elsewhere within the
-    /// enclosing type.  This means that, in an `impl Trait` context, we
+    /// enclosing type. This means that, in an `impl Trait` context, we
     /// don't have to create a parameter for them. That is, `impl
     /// Trait<Item = &u32>` expands to an opaque type like `type
     /// Foo<'a> = impl Trait<Item = &'a u32>`, but `impl Trait<item =
@@ -826,13 +826,11 @@ pub struct OwnerNodes<'tcx> {
     pub hash_without_bodies: Fingerprint,
     /// Full HIR for the current owner.
     // The zeroth node's parent should never be accessed: the owner's parent is computed by the
-    // hir_owner_parent query.  It is set to `ItemLocalId::INVALID` to force an ICE if accidentally
+    // hir_owner_parent query. It is set to `ItemLocalId::INVALID` to force an ICE if accidentally
     // used.
     pub nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
     /// Content of local bodies.
     pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>,
-    /// Non-owning definitions contained in this owner.
-    pub local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
 }
 
 impl<'tcx> OwnerNodes<'tcx> {
@@ -862,7 +860,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                     .collect::<Vec<_>>(),
             )
             .field("bodies", &self.bodies)
-            .field("local_id_to_def_id", &self.local_id_to_def_id)
             .field("hash_without_bodies", &self.hash_without_bodies)
             .field("hash_including_bodies", &self.hash_including_bodies)
             .finish()
@@ -1787,6 +1784,14 @@ pub fn peel_blocks(&self) -> &Self {
         expr
     }
 
+    pub fn peel_borrows(&self) -> &Self {
+        let mut expr = self;
+        while let ExprKind::AddrOf(.., inner) = &expr.kind {
+            expr = inner;
+        }
+        expr
+    }
+
     pub fn can_have_side_effects(&self) -> bool {
         match self.peel_drop_temps().kind {
             ExprKind::Path(_) | ExprKind::Lit(_) => false,
@@ -2098,8 +2103,8 @@ pub enum LocalSource {
 }
 
 /// Hints at the original code for a `match _ { .. }`.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)]
-#[derive(HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
 pub enum MatchSource {
     /// A `match _ { .. }`.
     Normal,
@@ -2109,6 +2114,8 @@ pub enum MatchSource {
     TryDesugar,
     /// A desugared `<expr>.await`.
     AwaitDesugar,
+    /// A desugared `format_args!()`.
+    FormatArgs,
 }
 
 impl MatchSource {
@@ -2120,6 +2127,7 @@ pub const fn name(self) -> &'static str {
             ForLoopDesugar => "for",
             TryDesugar => "?",
             AwaitDesugar => ".await",
+            FormatArgs => "format_args!()",
         }
     }
 }
@@ -3516,6 +3524,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 02641b7cf8fb5e037599f4d46e4c63eb3dcb9d29..f632babab0b24476b299f943d74ef2462d42afa7 100644 (file)
@@ -67,6 +67,7 @@
 use crate::hir::*;
 use rustc_ast::walk_list;
 use rustc_ast::{Attribute, Label};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
 
@@ -364,7 +365,7 @@ fn visit_fn_ret_ty(&mut self, ret_ty: &'v FnRetTy<'v>) {
     fn visit_fn_decl(&mut self, fd: &'v FnDecl<'v>) {
         walk_fn_decl(self, fd)
     }
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl<'v>, b: BodyId, _: Span, id: HirId) {
+    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl<'v>, b: BodyId, _: Span, id: LocalDefId) {
         walk_fn(self, fk, fd, b, id)
     }
     fn visit_use(&mut self, path: &'v UsePath<'v>, hir_id: HirId) {
@@ -468,13 +469,16 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
             visitor.visit_ty(typ);
             visitor.visit_nested_body(body);
         }
-        ItemKind::Fn(ref sig, ref generics, body_id) => visitor.visit_fn(
-            FnKind::ItemFn(item.ident, generics, sig.header),
-            sig.decl,
-            body_id,
-            item.span,
-            item.hir_id(),
-        ),
+        ItemKind::Fn(ref sig, ref generics, body_id) => {
+            visitor.visit_id(item.hir_id());
+            visitor.visit_fn(
+                FnKind::ItemFn(item.ident, generics, sig.header),
+                sig.decl,
+                body_id,
+                item.span,
+                item.owner_id.def_id,
+            )
+        }
         ItemKind::Macro(..) => {
             visitor.visit_id(item.hir_id());
         }
@@ -733,7 +737,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             walk_list!(visitor, visit_arm, arms);
         }
         ExprKind::Closure(&Closure {
-            def_id: _,
+            def_id,
             binder: _,
             bound_generic_params,
             fn_decl,
@@ -745,7 +749,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             constness: _,
         }) => {
             walk_list!(visitor, visit_generic_param, bound_generic_params);
-            visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
+            visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, def_id)
         }
         ExprKind::Block(ref block, ref opt_label) => {
             walk_list!(visitor, visit_label, opt_label);
@@ -923,9 +927,8 @@ pub fn walk_fn<'v, V: Visitor<'v>>(
     function_kind: FnKind<'v>,
     function_declaration: &'v FnDecl<'v>,
     body_id: BodyId,
-    id: HirId,
+    _: LocalDefId,
 ) {
-    visitor.visit_id(id);
     visitor.visit_fn_decl(function_declaration);
     walk_fn_kind(visitor, function_kind);
     visitor.visit_nested_body(body_id)
@@ -953,26 +956,30 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
     let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item;
     let hir_id = trait_item.hir_id();
     visitor.visit_ident(ident);
-    visitor.visit_generics(generics);
-    visitor.visit_defaultness(defaultness);
+    visitor.visit_generics(&generics);
+    visitor.visit_defaultness(&defaultness);
+    visitor.visit_id(hir_id);
     match *kind {
         TraitItemKind::Const(ref ty, default) => {
-            visitor.visit_id(hir_id);
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_nested_body, default);
         }
         TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => {
-            visitor.visit_id(hir_id);
             visitor.visit_fn_decl(sig.decl);
             for &param_name in param_names {
                 visitor.visit_ident(param_name);
             }
         }
         TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => {
-            visitor.visit_fn(FnKind::Method(ident, sig), sig.decl, body_id, span, hir_id);
+            visitor.visit_fn(
+                FnKind::Method(ident, sig),
+                sig.decl,
+                body_id,
+                span,
+                trait_item.owner_id.def_id,
+            );
         }
         TraitItemKind::Type(bounds, ref default) => {
-            visitor.visit_id(hir_id);
             walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_ty, default);
         }
@@ -1002,9 +1009,9 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
     visitor.visit_ident(ident);
     visitor.visit_generics(generics);
     visitor.visit_defaultness(defaultness);
+    visitor.visit_id(impl_item.hir_id());
     match *kind {
         ImplItemKind::Const(ref ty, body) => {
-            visitor.visit_id(impl_item.hir_id());
             visitor.visit_ty(ty);
             visitor.visit_nested_body(body);
         }
@@ -1014,11 +1021,10 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
                 sig.decl,
                 body_id,
                 impl_item.span,
-                impl_item.hir_id(),
+                impl_item.owner_id.def_id,
             );
         }
         ImplItemKind::Type(ref ty) => {
-            visitor.visit_id(impl_item.hir_id());
             visitor.visit_ty(ty);
         }
     }
index 3474fab34f00b1e70bb777ac1f43adaf783369ad..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);
@@ -291,6 +299,7 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     IdentityFuture,          sym::identity_future,     identity_future_fn,         Target::Fn,             GenericRequirement::None;
     GetContext,              sym::get_context,         get_context_fn,             Target::Fn,             GenericRequirement::None;
 
+    Context,                 sym::Context,             context,                    Target::Struct,         GenericRequirement::None;
     FuturePoll,              sym::poll,                future_poll_fn,             Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
 
     FromFrom,                sym::from,                from_fn,                    Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
index 23423e8f3b3bff5f7121730e857a190e665d8667..85d0e02d0b6834004ca51eacdd1bf62093e600e7 100644 (file)
@@ -100,13 +100,8 @@ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
         // `local_id_to_def_id` is also ignored because is dependent on the body, then just hashing
         // the body satisfies the condition of two nodes being different have different
         // `hash_stable` results.
-        let OwnerNodes {
-            hash_including_bodies,
-            hash_without_bodies: _,
-            nodes: _,
-            bodies: _,
-            local_id_to_def_id: _,
-        } = *self;
+        let OwnerNodes { hash_including_bodies, hash_without_bodies: _, nodes: _, bodies: _ } =
+            *self;
         hash_including_bodies.hash_stable(hcx, hasher);
     }
 }
index 5368dc0735bc1994e6e4135284ef9616dbb50820..232ef2079d6bb9eb3c37e95a0547ed2772c4ada9 100644 (file)
@@ -331,7 +331,7 @@ pub(crate) fn complain_about_missing_associated_types(
             }
             if potential_assoc_types.len() == assoc_items.len() {
                 // When the amount of missing associated types equals the number of
-                // extra type arguments present.  A suggesting to replace the generic args with
+                // extra type arguments present. A suggesting to replace the generic args with
                 // associated types is already emitted.
                 already_has_generics_args_suggestion = true;
             } else if let (Ok(snippet), false) =
index ce3682a8f2d5cda48084a4566eb84e76ccb4e9c4..7a499327dbf240f1f08e9874a417a24e3e31ee82 100644 (file)
@@ -337,13 +337,13 @@ pub fn create_substs_for_generic_args<'tcx, 'a>(
                     // We should never be able to reach this point with well-formed input.
                     // There are three situations in which we can encounter this issue.
                     //
-                    //  1.  The number of arguments is incorrect. In this case, an error
-                    //      will already have been emitted, and we can ignore it.
-                    //  2.  There are late-bound lifetime parameters present, yet the
-                    //      lifetime arguments have also been explicitly specified by the
-                    //      user.
-                    //  3.  We've inferred some lifetimes, which have been provided later (i.e.
-                    //      after a type or const). We want to throw an error in this case.
+                    //  1. The number of arguments is incorrect. In this case, an error
+                    //     will already have been emitted, and we can ignore it.
+                    //  2. There are late-bound lifetime parameters present, yet the
+                    //     lifetime arguments have also been explicitly specified by the
+                    //     user.
+                    //  3. We've inferred some lifetimes, which have been provided later (i.e.
+                    //     after a type or const). We want to throw an error in this case.
 
                     if arg_count.correct.is_ok()
                         && arg_count.explicit_late_bound == ExplicitLateBound::No
index 3521911b05527b23cda94b14211e018a0985bb32..caf26a75d3cc4c18b4bfabcac1af7e84875b0b09 100644 (file)
@@ -27,7 +27,7 @@
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{walk_generics, Visitor as _};
 use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
@@ -37,7 +37,7 @@
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::{sym, Span};
+use rustc_span::{sym, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::astconv_object_safety_violations;
@@ -54,7 +54,7 @@
 pub struct PathSeg(pub DefId, pub usize);
 
 pub trait AstConv<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
+    fn tcx(&self) -> TyCtxt<'tcx>;
 
     fn item_def_id(&self) -> DefId;
 
@@ -131,6 +131,8 @@ fn astconv(&self) -> &dyn AstConv<'tcx>
     {
         self
     }
+
+    fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
 }
 
 #[derive(Debug)]
@@ -511,9 +513,7 @@ fn inferred_kind(
                             return tcx.const_error(ty).into();
                         }
                         if !infer_args && has_default {
-                            tcx.bound_const_param_default(param.def_id)
-                                .subst(tcx, substs.unwrap())
-                                .into()
+                            tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
                         } else {
                             if infer_args {
                                 self.astconv.ct_infer(ty, Some(param), self.span).into()
@@ -571,17 +571,17 @@ fn create_assoc_bindings_for_generic_args<'a>(
             .bindings
             .iter()
             .map(|binding| {
-                let kind = match binding.kind {
-                    hir::TypeBindingKind::Equality { ref term } => match term {
-                        hir::Term::Ty(ref ty) => {
+                let kind = match &binding.kind {
+                    hir::TypeBindingKind::Equality { term } => match term {
+                        hir::Term::Ty(ty) => {
                             ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
                         }
-                        hir::Term::Const(ref c) => {
+                        hir::Term::Const(c) => {
                             let c = Const::from_anon_const(self.tcx(), c.def_id);
                             ConvertedBindingKind::Equality(c.into())
                         }
                     },
-                    hir::TypeBindingKind::Constraint { ref bounds } => {
+                    hir::TypeBindingKind::Constraint { bounds } => {
                         ConvertedBindingKind::Constraint(bounds)
                     }
                 };
@@ -994,7 +994,7 @@ pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>
     /// ```
     ///
     /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be
-    /// considered `Sized` unless there is an explicit `?Sized` bound.  This would be true in the
+    /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the
     /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`.
     ///
     /// `span` should be the declaration size of the parameter.
@@ -1499,7 +1499,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
             i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
                 assert_eq!(trait_ref.self_ty(), dummy_self);
 
-                // Verify that `dummy_self` did not leak inside default type parameters.  This
+                // Verify that `dummy_self` did not leak inside default type parameters. This
                 // could not be done at path creation, since we need to see through trait aliases.
                 let mut missing_type_params = vec![];
                 let mut references_self = false;
@@ -1930,7 +1930,7 @@ pub fn associated_path_to_ty(
     ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
         let tcx = self.tcx();
         let assoc_ident = assoc_segment.ident;
-        let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind {
+        let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
             path.res
         } else {
             Res::Err
@@ -1973,8 +1973,8 @@ pub fn associated_path_to_ty(
                                 return;
                             };
                             let (qself_sugg_span, is_self) = if let hir::TyKind::Path(
-                                hir::QPath::Resolved(_, ref path)
-                            ) = qself.kind {
+                                hir::QPath::Resolved(_, path)
+                            ) = &qself.kind {
                                 // If the path segment already has type params, we want to overwrite
                                 // them.
                                 match &path.segments[..] {
@@ -2068,7 +2068,7 @@ pub fn associated_path_to_ty(
                 };
 
                 self.one_bound_for_assoc_type(
-                    || traits::supertraits(tcx, ty::Binder::dummy(trait_ref)),
+                    || traits::supertraits(tcx, ty::Binder::dummy(trait_ref.subst_identity())),
                     || "Self".to_string(),
                     assoc_ident,
                     span,
@@ -2134,48 +2134,8 @@ pub fn associated_path_to_ty(
                     )
                     .emit() // Already reported in an earlier stage.
                 } else {
-                    // Find all the `impl`s that `qself_ty` has for any trait that has the
-                    // associated type, so that we suggest the right one.
-                    let infcx = tcx.infer_ctxt().build();
-                    // We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()`
-                    // to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`.
-                    let param_env = ty::ParamEnv::empty();
-                    let traits: Vec<_> = self
-                        .tcx()
-                        .all_traits()
-                        .filter(|trait_def_id| {
-                            // Consider only traits with the associated type
-                            tcx.associated_items(*trait_def_id)
-                                .in_definition_order()
-                                .any(|i| {
-                                    i.kind.namespace() == Namespace::TypeNS
-                                        && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
-                                        && matches!(i.kind, ty::AssocKind::Type)
-                                })
-                            // Consider only accessible traits
-                            && tcx.visibility(*trait_def_id)
-                                .is_accessible_from(self.item_def_id(), tcx)
-                            && tcx.all_impls(*trait_def_id)
-                                .any(|impl_def_id| {
-                                    let trait_ref = tcx.bound_impl_trait_ref(impl_def_id);
-                                    trait_ref.map_or(false, |trait_ref| {
-                                        let impl_ = trait_ref.subst(
-                                            tcx,
-                                            infcx.fresh_substs_for_item(span, impl_def_id),
-                                        );
-                                        infcx
-                                            .can_eq(
-                                                param_env,
-                                                tcx.erase_regions(impl_.self_ty()),
-                                                tcx.erase_regions(qself_ty),
-                                            )
-                                            .is_ok()
-                                    })
-                                    && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
-                                })
-                        })
-                        .map(|trait_def_id| tcx.def_path_str(trait_def_id))
-                        .collect();
+                    let traits: Vec<_> =
+                        self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
 
                     // Don't print `TyErr` to the user.
                     self.report_ambiguous_associated_type(
@@ -2234,6 +2194,60 @@ pub fn associated_path_to_ty(
         Ok((ty, DefKind::AssocTy, assoc_ty_did))
     }
 
+    fn probe_traits_that_match_assoc_ty(
+        &self,
+        qself_ty: Ty<'tcx>,
+        assoc_ident: Ident,
+    ) -> Vec<String> {
+        let tcx = self.tcx();
+
+        // In contexts that have no inference context, just make a new one.
+        // We do need a local variable to store it, though.
+        let infcx_;
+        let infcx = if let Some(infcx) = self.infcx() {
+            infcx
+        } else {
+            assert!(!qself_ty.needs_infer());
+            infcx_ = tcx.infer_ctxt().build();
+            &infcx_
+        };
+
+        tcx.all_traits()
+            .filter(|trait_def_id| {
+                // Consider only traits with the associated type
+                tcx.associated_items(*trait_def_id)
+                        .in_definition_order()
+                        .any(|i| {
+                            i.kind.namespace() == Namespace::TypeNS
+                                && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
+                                && matches!(i.kind, ty::AssocKind::Type)
+                        })
+                    // Consider only accessible traits
+                    && tcx.visibility(*trait_def_id)
+                        .is_accessible_from(self.item_def_id(), tcx)
+                    && tcx.all_impls(*trait_def_id)
+                        .any(|impl_def_id| {
+                            let trait_ref = tcx.impl_trait_ref(impl_def_id);
+                            trait_ref.map_or(false, |trait_ref| {
+                                let impl_ = trait_ref.subst(
+                                    tcx,
+                                    infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id),
+                                );
+                                infcx
+                                    .can_eq(
+                                        ty::ParamEnv::empty(),
+                                        tcx.erase_regions(impl_.self_ty()),
+                                        tcx.erase_regions(qself_ty),
+                                    )
+                                    .is_ok()
+                            })
+                            && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
+                        })
+            })
+            .map(|trait_def_id| tcx.def_path_str(trait_def_id))
+            .collect()
+    }
+
     fn lookup_assoc_ty(
         &self,
         ident: Ident,
@@ -2310,7 +2324,7 @@ fn qpath_to_ty(
                             && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
                     })
                     .filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id))
-                    .map(|impl_| impl_.self_ty())
+                    .map(|impl_| impl_.subst_identity().self_ty())
                     // We don't care about blanket impls.
                     .filter(|self_ty| !self_ty.has_non_region_param())
                     .map(|self_ty| tcx.erase_regions(self_ty).to_string())
@@ -2604,7 +2618,7 @@ pub fn res_to_ty(
         match path.res {
             Res::Def(DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder, did) => {
                 // Check for desugared `impl Trait`.
-                assert!(ty::is_impl_trait_defn(tcx, did).is_none());
+                assert!(tcx.is_type_alias_impl_trait(did));
                 let item_segment = path.segments.split_last().unwrap();
                 self.prohibit_generics(item_segment.1.iter(), |err| {
                     err.note("`impl Trait` types can't have type parameters");
@@ -2762,7 +2776,7 @@ pub fn res_to_ty(
                         "generic `Self` types are currently not permitted in anonymous constants",
                     );
                     if let Some(hir::Node::Item(&hir::Item {
-                        kind: hir::ItemKind::Impl(ref impl_),
+                        kind: hir::ItemKind::Impl(impl_),
                         ..
                     })) = tcx.hir().get_if_local(def_id)
                     {
@@ -2834,7 +2848,7 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
     }
 
     /// Parses the programmer's textual representation of a type into our
-    /// internal notion of a type.  This is meant to be used within a path.
+    /// internal notion of a type. This is meant to be used within a path.
     pub fn ast_ty_to_ty_in_path(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
         self.ast_ty_to_ty_inner(ast_ty, false, true)
     }
@@ -2845,12 +2859,12 @@ pub fn ast_ty_to_ty_in_path(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
     fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> {
         let tcx = self.tcx();
 
-        let result_ty = match ast_ty.kind {
-            hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)),
-            hir::TyKind::Ptr(ref mt) => {
+        let result_ty = match &ast_ty.kind {
+            hir::TyKind::Slice(ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)),
+            hir::TyKind::Ptr(mt) => {
                 tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
             }
-            hir::TyKind::Ref(ref region, ref mt) => {
+            hir::TyKind::Ref(region, mt) => {
                 let r = self.ast_region_to_region(region, None);
                 debug!(?r);
                 let t = self.ast_ty_to_ty_inner(mt.ty, true, false);
@@ -2870,7 +2884,7 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                     Some(ast_ty),
                 ))
             }
-            hir::TyKind::TraitObject(bounds, ref lifetime, repr) => {
+            hir::TyKind::TraitObject(bounds, lifetime, repr) => {
                 self.maybe_lint_bare_trait(ast_ty, in_path);
                 let repr = match repr {
                     TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
@@ -2878,12 +2892,12 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                 };
                 self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr)
             }
-            hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
+            hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
                 debug!(?maybe_qself, ?path);
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself));
                 self.res_to_ty(opt_self_ty, path, false)
             }
-            hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
+            &hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
                 let opaque_ty = tcx.hir().item(item_id);
                 let def_id = item_id.owner_id.to_def_id();
 
@@ -2894,14 +2908,14 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                     ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
                 }
             }
-            hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
+            hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
                 debug!(?qself, ?segment);
                 let ty = self.ast_ty_to_ty_inner(qself, false, true);
                 self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false)
                     .map(|(ty, _, _)| ty)
                     .unwrap_or_else(|_| tcx.ty_error())
             }
-            hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => {
+            &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => {
                 let def_id = tcx.require_lang_item(lang_item, Some(span));
                 let (substs, _) = self.create_substs_for_ast_path(
                     span,
@@ -2915,7 +2929,7 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                 );
                 EarlyBinder(tcx.at(span).type_of(def_id)).subst(tcx, substs)
             }
-            hir::TyKind::Array(ref ty, ref length) => {
+            hir::TyKind::Array(ty, length) => {
                 let length = match length {
                     &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
                     hir::ArrayLen::Body(constant) => {
@@ -2925,7 +2939,7 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
 
                 tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length))
             }
-            hir::TyKind::Typeof(ref e) => {
+            hir::TyKind::Typeof(e) => {
                 let ty_erased = tcx.type_of(e.def_id);
                 let ty = tcx.fold_regions(ty_erased, |r, _| {
                     if r.is_erased() { tcx.lifetimes.re_static } else { r }
@@ -3142,7 +3156,7 @@ fn suggest_trait_fn_ty_for_impl_fn_infer(
             trait_ref.def_id,
         )?;
 
-        let fn_sig = tcx.bound_fn_sig(assoc.def_id).subst(
+        let fn_sig = tcx.fn_sig(assoc.def_id).subst(
             tcx,
             trait_ref.substs.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)),
         );
@@ -3307,7 +3321,13 @@ fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
                 let label = "add `dyn` keyword before this trait";
                 let mut diag =
                     rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
-                diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
+                if self_ty.span.can_be_used_for_suggestions() {
+                    diag.multipart_suggestion_verbose(
+                        label,
+                        sugg,
+                        Applicability::MachineApplicable,
+                    );
+                }
                 // check if the impl trait that we are considering is a impl of a local trait
                 self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
                 diag.emit();
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 43795cfba3fd81edc85efcd69526445e26c82a54..6f4ebc987e6a97ee0951550e5c894f76a68f8f41 100644 (file)
@@ -14,7 +14,7 @@
 use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
-use rustc_infer::traits::Obligation;
+use rustc_infer::traits::{Obligation, TraitEngineExt as _};
 use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::stability::EvalResult;
@@ -28,7 +28,7 @@
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{self, ObligationCtxt};
+use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _};
 
 use std::ops::ControlFlow;
 
@@ -267,7 +267,7 @@ impl<'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             debug!(?t, "root_visit_ty");
             if t == self.opaque_identity_ty {
-                ControlFlow::CONTINUE
+                ControlFlow::Continue(())
             } else {
                 t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
                     tcx: self.tcx,
@@ -282,7 +282,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if self.references_parent_regions {
                     ControlFlow::Break(t)
                 } else {
-                    ControlFlow::CONTINUE
+                    ControlFlow::Continue(())
                 }
             }
         }
@@ -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(()) => {}
@@ -531,16 +530,14 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
         DefKind::Fn => {} // entirely within check_item_body
         DefKind::Impl => {
             let it = tcx.hir().item(id);
-            let hir::ItemKind::Impl(ref impl_) = it.kind else {
-                return;
-            };
+            let hir::ItemKind::Impl(impl_) = it.kind else { return };
             debug!("ItemKind::Impl {} with id {:?}", it.ident, it.owner_id);
             if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.owner_id) {
                 check_impl_items_against_trait(
                     tcx,
                     it.span,
                     it.owner_id.def_id,
-                    impl_trait_ref,
+                    impl_trait_ref.subst_identity(),
                     &impl_.items,
                 );
                 check_on_unimplemented(tcx, it);
@@ -548,15 +545,15 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
         }
         DefKind::Trait => {
             let it = tcx.hir().item(id);
-            let hir::ItemKind::Trait(_, _, _, _, ref items) = it.kind else {
+            let hir::ItemKind::Trait(_, _, _, _, items) = it.kind else {
                 return;
             };
             check_on_unimplemented(tcx, it);
 
             for item in items.iter() {
                 let item = tcx.hir().trait_item(item.id);
-                match item.kind {
-                    hir::TraitItemKind::Fn(ref sig, _) => {
+                match &item.kind {
+                    hir::TraitItemKind::Fn(sig, _) => {
                         let abi = sig.header.abi;
                         fn_maybe_err(tcx, item.ident.span, abi);
                     }
@@ -652,8 +649,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
                     }
 
                     let item = tcx.hir().foreign_item(item.id);
-                    match item.kind {
-                        hir::ForeignItemKind::Fn(ref fn_decl, _, _) => {
+                    match &item.kind {
+                        hir::ForeignItemKind::Fn(fn_decl, _, _) => {
                             require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span);
                         }
                         hir::ForeignItemKind::Static(..) => {
@@ -668,7 +665,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
         DefKind::GlobalAsm => {
             let it = tcx.hir().item(id);
             let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) };
-            InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.hir_id());
+            InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id);
         }
         _ => {}
     }
@@ -1393,11 +1390,15 @@ fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed
 ///
 /// If all the return expressions evaluate to `!`, then we explain that the error will go away
 /// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
-fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> ErrorGuaranteed {
+fn opaque_type_cycle_error(
+    tcx: TyCtxt<'_>,
+    opaque_def_id: LocalDefId,
+    span: Span,
+) -> ErrorGuaranteed {
     let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
 
     let mut label = false;
-    if let Some((def_id, visitor)) = get_owner_return_paths(tcx, def_id) {
+    if let Some((def_id, visitor)) = get_owner_return_paths(tcx, opaque_def_id) {
         let typeck_results = tcx.typeck(def_id);
         if visitor
             .returns
@@ -1433,28 +1434,72 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E
                 .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
                 .filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
             {
-                struct OpaqueTypeCollector(Vec<DefId>);
+                #[derive(Default)]
+                struct OpaqueTypeCollector {
+                    opaques: Vec<DefId>,
+                    closures: Vec<DefId>,
+                }
                 impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector {
                     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                         match *t.kind() {
                             ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
-                                self.0.push(def);
-                                ControlFlow::CONTINUE
+                                self.opaques.push(def);
+                                ControlFlow::Continue(())
+                            }
+                            ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => {
+                                self.closures.push(def_id);
+                                t.super_visit_with(self)
                             }
                             _ => t.super_visit_with(self),
                         }
                     }
                 }
-                let mut visitor = OpaqueTypeCollector(vec![]);
+
+                let mut visitor = OpaqueTypeCollector::default();
                 ty.visit_with(&mut visitor);
-                for def_id in visitor.0 {
+                for def_id in visitor.opaques {
                     let ty_span = tcx.def_span(def_id);
                     if !seen.contains(&ty_span) {
-                        err.span_label(ty_span, &format!("returning this opaque type `{ty}`"));
+                        let descr = if ty.is_impl_trait() { "opaque " } else { "" };
+                        err.span_label(ty_span, &format!("returning this {descr}type `{ty}`"));
                         seen.insert(ty_span);
                     }
                     err.span_label(sp, &format!("returning here with type `{ty}`"));
                 }
+
+                for closure_def_id in visitor.closures {
+                    let Some(closure_local_did) = closure_def_id.as_local() else { continue; };
+                    let typeck_results = tcx.typeck(closure_local_did);
+
+                    let mut label_match = |ty: Ty<'_>, span| {
+                        for arg in ty.walk() {
+                            if let ty::GenericArgKind::Type(ty) = arg.unpack()
+                                && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: captured_def_id, .. }) = *ty.kind()
+                                && captured_def_id == opaque_def_id.to_def_id()
+                            {
+                                err.span_label(
+                                    span,
+                                    format!(
+                                        "{} captures itself here",
+                                        tcx.def_kind(closure_def_id).descr(closure_def_id)
+                                    ),
+                                );
+                            }
+                        }
+                    };
+
+                    // Label any closure upvars that capture the opaque
+                    for capture in typeck_results.closure_min_captures_flattened(closure_local_did)
+                    {
+                        label_match(capture.place.ty(), capture.get_path_span(tcx));
+                    }
+                    // Label any generator locals that capture the opaque
+                    for interior_ty in
+                        typeck_results.generator_interior_types.as_ref().skip_binder()
+                    {
+                        label_match(interior_ty.ty, interior_ty.span);
+                    }
+                }
             }
         }
     }
@@ -1463,3 +1508,34 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
     }
     err.emit()
 }
+
+pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+    debug_assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir);
+    debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Generator));
+
+    let typeck = tcx.typeck(def_id);
+    let param_env = tcx.param_env(def_id);
+
+    let generator_interior_predicates = &typeck.generator_interior_predicates[&def_id];
+    debug!(?generator_interior_predicates);
+
+    let infcx = tcx
+        .infer_ctxt()
+        // typeck writeback gives us predicates with their regions erased.
+        // As borrowck already has checked lifetimes, we do not need to do it again.
+        .ignoring_regions()
+        // Bind opaque types to `def_id` as they should have been checked by borrowck.
+        .with_opaque_type_inference(DefiningAnchor::Bind(def_id))
+        .build();
+
+    let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+    for (predicate, cause) in generator_interior_predicates {
+        let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
+        fulfillment_cx.register_predicate_obligation(&infcx, obligation);
+    }
+    let errors = fulfillment_cx.select_all_or_error(&infcx);
+    debug!(?errors);
+    if !errors.is_empty() {
+        infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+    }
+}
index 2cdf75794713fe67666bc377a607976422e188ba..780d5271619e7ef90a4af4a0172eb7aaf639ad80 100644 (file)
@@ -47,42 +47,22 @@ pub(super) fn compare_impl_method<'tcx>(
 
     let impl_m_span = tcx.def_span(impl_m.def_id);
 
-    if let Err(_) = compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref) {
-        return;
-    }
-
-    if let Err(_) = compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false) {
-        return;
-    }
-
-    if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, false) {
-        return;
-    }
-
-    if let Err(_) =
-        compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
-    {
-        return;
-    }
-
-    if let Err(_) = compare_synthetic_generics(tcx, impl_m, trait_m) {
-        return;
-    }
-
-    if let Err(_) = compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span) {
-        return;
-    }
-
-    if let Err(_) = compare_method_predicate_entailment(
-        tcx,
-        impl_m,
-        impl_m_span,
-        trait_m,
-        impl_trait_ref,
-        CheckImpliedWfMode::Check,
-    ) {
-        return;
-    }
+    let _: Result<_, ErrorGuaranteed> = try {
+        compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)?;
+        compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false)?;
+        compare_generic_param_kinds(tcx, impl_m, trait_m, false)?;
+        compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)?;
+        compare_synthetic_generics(tcx, impl_m, trait_m)?;
+        compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span)?;
+        compare_method_predicate_entailment(
+            tcx,
+            impl_m,
+            impl_m_span,
+            trait_m,
+            impl_trait_ref,
+            CheckImpliedWfMode::Check,
+        )?;
+    };
 }
 
 /// This function is best explained by example. Consider a trait:
@@ -138,7 +118,7 @@ pub(super) fn compare_impl_method<'tcx>(
 ///     <'a> fn(t: &'i0 U0, m: &'a) -> Foo
 ///
 /// This type is also the same but the name of the bound region (`'a`
-/// vs `'b`).  However, the normal subtyping rules on fn types handle
+/// vs `'b`). However, the normal subtyping rules on fn types handle
 /// this kind of equivalency just fine.
 ///
 /// We now use these substitutions to ensure that all declared bounds are
@@ -167,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,
         },
@@ -209,14 +189,16 @@ fn compare_method_predicate_entailment<'tcx>(
     //
     // We then register the obligations from the impl_m and check to see
     // if all constraints hold.
-    hybrid_preds
-        .predicates
-        .extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates);
+    hybrid_preds.predicates.extend(
+        trait_m_predicates
+            .instantiate_own(tcx, trait_to_placeholder_substs)
+            .map(|(predicate, _)| predicate),
+    );
 
     // 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,
@@ -230,15 +212,15 @@ fn compare_method_predicate_entailment<'tcx>(
     debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
 
     let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
-    for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
-        let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
+    for (predicate, span) in impl_m_own_bounds {
+        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,
             },
@@ -267,15 +249,15 @@ fn compare_method_predicate_entailment<'tcx>(
     let unnormalized_impl_sig = infcx.replace_bound_vars_with_fresh_vars(
         impl_m_span,
         infer::HigherRankedType,
-        tcx.fn_sig(impl_m.def_id),
+        tcx.fn_sig(impl_m.def_id).subst_identity(),
     );
     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);
 
-    let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
+    let trait_sig = tcx.fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
     let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
 
     // Next, add all inputs and output as well-formed tys. Importantly,
@@ -329,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,
@@ -354,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(),
@@ -364,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(
@@ -389,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
@@ -438,8 +422,8 @@ fn extract_bad_args_for_implies_lint<'tcx>(
 
     // Map late-bound regions from trait to impl, so the names are right.
     let mapping = std::iter::zip(
-        tcx.fn_sig(trait_m.def_id).bound_vars(),
-        tcx.fn_sig(impl_m.def_id).bound_vars(),
+        tcx.fn_sig(trait_m.def_id).skip_binder().bound_vars(),
+        tcx.fn_sig(impl_m.def_id).skip_binder().bound_vars(),
     )
     .filter_map(|(impl_bv, trait_bv)| {
         if let ty::BoundVariableKind::Region(impl_bv) = impl_bv
@@ -556,7 +540,7 @@ fn compare_asyncness<'tcx>(
     trait_item_span: Option<Span>,
 ) -> Result<(), ErrorGuaranteed> {
     if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
-        match tcx.fn_sig(impl_m.def_id).skip_binder().output().kind() {
+        match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() {
             ty::Alias(ty::Opaque, ..) => {
                 // allow both `async fn foo()` and `fn foo() -> impl Future`
             }
@@ -616,7 +600,8 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
 ) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
     let impl_m = tcx.opt_associated_item(def_id).unwrap();
     let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
-    let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
+    let impl_trait_ref =
+        tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().subst_identity();
     let param_env = tcx.param_env(def_id);
 
     // First, check a few of the same things as `compare_impl_method`,
@@ -627,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,
         },
@@ -650,14 +636,14 @@ 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,
         infcx.replace_bound_vars_with_fresh_vars(
             return_span,
             infer::HigherRankedType,
-            tcx.fn_sig(impl_m.def_id),
+            tcx.fn_sig(impl_m.def_id).subst_identity(),
         ),
     );
     impl_sig.error_reported()?;
@@ -667,11 +653,11 @@ 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,
-            tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
+            tcx.fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
         )
         .fold_with(&mut collector);
     let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
@@ -749,19 +735,18 @@ 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 {
         match infcx.fully_resolve(ty) {
             Ok(ty) => {
                 // `ty` contains free regions that we created earlier while liberating the
-                // trait fn signature.  However, projection normalization expects `ty` to
+                // trait fn signature. However, projection normalization expects `ty` to
                 // contains `def_id`'s early-bound regions.
                 let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
                 debug!(?id_substs, ?substs);
@@ -836,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> {
@@ -844,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 }
     }
@@ -933,16 +918,14 @@ fn report_trait_method_mismatch<'tcx>(
             // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
             // span points only at the type `Box<Self`>, but we want to cover the whole
             // argument pattern and type.
-            let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
-                ImplItemKind::Fn(ref sig, body) => tcx
-                    .hir()
-                    .body_param_names(body)
-                    .zip(sig.decl.inputs.iter())
-                    .map(|(param, ty)| param.span.to(ty.span))
-                    .next()
-                    .unwrap_or(impl_err_span),
-                _ => bug!("{:?} is not a method", impl_m),
-            };
+            let ImplItemKind::Fn(ref sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{impl_m:?} is not a method") };
+            let span = tcx
+                .hir()
+                .body_param_names(body)
+                .zip(sig.decl.inputs.iter())
+                .map(|(param, ty)| param.span.to(ty.span))
+                .next()
+                .unwrap_or(impl_err_span);
 
             diag.span_suggestion(
                 span,
@@ -955,22 +938,21 @@ fn report_trait_method_mismatch<'tcx>(
             if trait_sig.inputs().len() == *i {
                 // Suggestion to change output type. We do not suggest in `async` functions
                 // to avoid complex logic or incorrect output.
-                match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
-                    ImplItemKind::Fn(ref sig, _) if !sig.header.asyncness.is_async() => {
-                        let msg = "change the output type to match the trait";
-                        let ap = Applicability::MachineApplicable;
-                        match sig.decl.output {
-                            hir::FnRetTy::DefaultReturn(sp) => {
-                                let sugg = format!("-> {} ", trait_sig.output());
-                                diag.span_suggestion_verbose(sp, msg, sugg, ap);
-                            }
-                            hir::FnRetTy::Return(hir_ty) => {
-                                let sugg = trait_sig.output();
-                                diag.span_suggestion(hir_ty.span, msg, sugg, ap);
-                            }
-                        };
-                    }
-                    _ => {}
+                if let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind
+                    && !sig.header.asyncness.is_async()
+                {
+                    let msg = "change the output type to match the trait";
+                    let ap = Applicability::MachineApplicable;
+                    match sig.decl.output {
+                        hir::FnRetTy::DefaultReturn(sp) => {
+                            let sugg = format!("-> {} ", trait_sig.output());
+                            diag.span_suggestion_verbose(sp, msg, sugg, ap);
+                        }
+                        hir::FnRetTy::Return(hir_ty) => {
+                            let sugg = trait_sig.output();
+                            diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+                        }
+                    };
                 };
             } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
                 diag.span_suggestion(
@@ -1019,7 +1001,7 @@ fn check_region_bounds_on_impl_item<'tcx>(
 
     // Must have same number of early-bound lifetime parameters.
     // Unfortunately, if the user screws up the bounds, then this
-    // will change classification between early and late.  E.g.,
+    // will change classification between early and late. E.g.,
     // if in trait we have `<'a,'b:'a>`, and in impl we just have
     // `<'a,'b>`, then we have 2 early-bound lifetime parameters
     // in trait but 0 in the impl. But if we report "expected 2
@@ -1097,25 +1079,18 @@ fn extract_spans_for_error_reporting<'tcx>(
     trait_m: &ty::AssocItem,
 ) -> (Span, Option<Span>) {
     let tcx = infcx.tcx;
-    let mut impl_args = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
-        ImplItemKind::Fn(ref sig, _) => {
-            sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
-        }
-        _ => bug!("{:?} is not a method", impl_m),
+    let mut impl_args = {
+        let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) };
+        sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
     };
-    let trait_args =
-        trait_m.def_id.as_local().map(|def_id| match tcx.hir().expect_trait_item(def_id).kind {
-            TraitItemKind::Fn(ref sig, _) => {
-                sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
-            }
-            _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
-        });
+
+    let trait_args = trait_m.def_id.as_local().map(|def_id| {
+        let TraitItemKind::Fn(sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a TraitItemKind::Fn", trait_m) };
+        sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
+    });
 
     match terr {
-        TypeError::ArgumentMutability(i) => {
-            (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
-        }
-        TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
+        TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
             (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
         }
         _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)),
@@ -1130,9 +1105,9 @@ fn compare_self_type<'tcx>(
     impl_trait_ref: ty::TraitRef<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
     // Try to give more informative error messages about self typing
-    // mismatches.  Note that any mismatch will also be detected
+    // mismatches. Note that any mismatch will also be detected
     // below, where we construct a canonical function type that
-    // includes the self parameter as a normal parameter.  It's just
+    // includes the self parameter as a normal parameter. It's just
     // that the error messages you get out of this code are a bit more
     // inscrutable, particularly for cases where one method has no
     // self.
@@ -1142,7 +1117,7 @@ fn compare_self_type<'tcx>(
             ty::ImplContainer => impl_trait_ref.self_ty(),
             ty::TraitContainer => tcx.types.self_param,
         };
-        let self_arg_ty = tcx.fn_sig(method.def_id).input(0);
+        let self_arg_ty = tcx.fn_sig(method.def_id).subst_identity().input(0);
         let param_env = ty::ParamEnv::reveal_all();
 
         let infcx = tcx.infer_ctxt().build();
@@ -1175,8 +1150,7 @@ fn compare_self_type<'tcx>(
             } else {
                 err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
             }
-            let reported = err.emit();
-            return Err(reported);
+            return Err(err.emit());
         }
 
         (true, false) => {
@@ -1195,8 +1169,8 @@ fn compare_self_type<'tcx>(
             } else {
                 err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
             }
-            let reported = err.emit();
-            return Err(reported);
+
+            return Err(err.emit());
         }
     }
 
@@ -1376,43 +1350,41 @@ fn compare_number_of_method_arguments<'tcx>(
 ) -> Result<(), ErrorGuaranteed> {
     let impl_m_fty = tcx.fn_sig(impl_m.def_id);
     let trait_m_fty = tcx.fn_sig(trait_m.def_id);
-    let trait_number_args = trait_m_fty.inputs().skip_binder().len();
-    let impl_number_args = impl_m_fty.inputs().skip_binder().len();
+    let trait_number_args = trait_m_fty.skip_binder().inputs().skip_binder().len();
+    let impl_number_args = impl_m_fty.skip_binder().inputs().skip_binder().len();
+
     if trait_number_args != impl_number_args {
-        let trait_span = if let Some(def_id) = trait_m.def_id.as_local() {
-            match tcx.hir().expect_trait_item(def_id).kind {
-                TraitItemKind::Fn(ref trait_m_sig, _) => {
-                    let pos = if trait_number_args > 0 { trait_number_args - 1 } else { 0 };
-                    if let Some(arg) = trait_m_sig.decl.inputs.get(pos) {
-                        Some(if pos == 0 {
-                            arg.span
-                        } else {
-                            arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
-                        })
-                    } else {
-                        trait_item_span
-                    }
-                }
-                _ => bug!("{:?} is not a method", impl_m),
-            }
-        } else {
-            trait_item_span
-        };
-        let impl_span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
-            ImplItemKind::Fn(ref impl_m_sig, _) => {
-                let pos = if impl_number_args > 0 { impl_number_args - 1 } else { 0 };
-                if let Some(arg) = impl_m_sig.decl.inputs.get(pos) {
+        let trait_span = trait_m
+            .def_id
+            .as_local()
+            .and_then(|def_id| {
+                let TraitItemKind::Fn(trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a method", impl_m) };
+                let pos = trait_number_args.saturating_sub(1);
+                trait_m_sig.decl.inputs.get(pos).map(|arg| {
                     if pos == 0 {
                         arg.span
                     } else {
-                        arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
+                        arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
                     }
+                })
+            })
+            .or(trait_item_span);
+
+        let ImplItemKind::Fn(impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) };
+        let pos = impl_number_args.saturating_sub(1);
+        let impl_span = impl_m_sig
+            .decl
+            .inputs
+            .get(pos)
+            .map(|arg| {
+                if pos == 0 {
+                    arg.span
                 } else {
-                    impl_m_span
+                    arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
                 }
-            }
-            _ => bug!("{:?} is not a method", impl_m),
-        };
+            })
+            .unwrap_or(impl_m_span);
+
         let mut err = struct_span_err!(
             tcx.sess,
             impl_span,
@@ -1423,6 +1395,7 @@ fn compare_number_of_method_arguments<'tcx>(
             tcx.def_path_str(trait_m.def_id),
             trait_number_args
         );
+
         if let Some(trait_span) = trait_span {
             err.span_label(
                 trait_span,
@@ -1434,6 +1407,7 @@ fn compare_number_of_method_arguments<'tcx>(
         } else {
             err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
         }
+
         err.span_label(
             impl_span,
             format!(
@@ -1442,8 +1416,8 @@ fn compare_number_of_method_arguments<'tcx>(
                 impl_number_args
             ),
         );
-        let reported = err.emit();
-        return Err(reported);
+
+        return Err(err.emit());
     }
 
     Ok(())
@@ -1490,7 +1464,7 @@ fn compare_synthetic_generics<'tcx>(
                 // explicit generics
                 (true, false) => {
                     err.span_label(impl_span, "expected generic parameter, found `impl Trait`");
-                    (|| {
+                    let _: Option<_> = try {
                         // try taking the name from the trait impl
                         // FIXME: this is obviously suboptimal since the name can already be used
                         // as another generic argument
@@ -1523,26 +1497,23 @@ fn compare_synthetic_generics<'tcx>(
                             ],
                             Applicability::MaybeIncorrect,
                         );
-                        Some(())
-                    })();
+                    };
                 }
                 // The case where the trait method uses `impl Trait`, but the impl method uses
                 // explicit generics.
                 (false, true) => {
                     err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
-                    (|| {
+                    let _: Option<_> = try {
                         let impl_m = impl_m.def_id.as_local()?;
                         let impl_m = tcx.hir().expect_impl_item(impl_m);
-                        let input_tys = match impl_m.kind {
-                            hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
-                            _ => unreachable!(),
-                        };
+                        let hir::ImplItemKind::Fn(sig, _) = &impl_m.kind else { unreachable!() };
+                        let input_tys = sig.decl.inputs;
+
                         struct Visitor(Option<Span>, hir::def_id::LocalDefId);
                         impl<'v> intravisit::Visitor<'v> for Visitor {
                             fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
                                 intravisit::walk_ty(self, ty);
-                                if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) =
-                                    ty.kind
+                                if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind
                                     && let Res::Def(DefKind::TyParam, def_id) = path.res
                                     && def_id == self.1.to_def_id()
                                 {
@@ -1550,6 +1521,7 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
                                 }
                             }
                         }
+
                         let mut visitor = Visitor(None, impl_def_id);
                         for ty in input_tys {
                             intravisit::Visitor::visit_ty(&mut visitor, ty);
@@ -1570,13 +1542,11 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
                             ],
                             Applicability::MaybeIncorrect,
                         );
-                        Some(())
-                    })();
+                    };
                 }
                 _ => unreachable!(),
             }
-            let reported = err.emit();
-            error_found = Some(reported);
+            error_found = Some(err.emit());
         }
     }
     if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
@@ -1684,7 +1654,8 @@ pub(super) fn compare_impl_const_raw(
 ) -> Result<(), ErrorGuaranteed> {
     let impl_const_item = tcx.associated_item(impl_const_item_def);
     let trait_const_item = tcx.associated_item(trait_const_item_def);
-    let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap();
+    let impl_trait_ref =
+        tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().subst_identity();
     debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
 
     let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
@@ -1702,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,
@@ -1735,10 +1704,8 @@ pub(super) fn compare_impl_const_raw(
         );
 
         // Locate the Span containing just the type of the offending impl
-        match tcx.hir().expect_impl_item(impl_const_item_def).kind {
-            ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
-            _ => bug!("{:?} is not a impl const", impl_const_item),
-        }
+        let ImplItemKind::Const(ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).kind else { bug!("{impl_const_item:?} is not a impl const") };
+        cause.span = ty.span;
 
         let mut diag = struct_span_err!(
             tcx.sess,
@@ -1750,10 +1717,8 @@ pub(super) fn compare_impl_const_raw(
 
         let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
             // Add a label to the Span containing just the type of the const
-            match tcx.hir().expect_trait_item(trait_c_def_id).kind {
-                TraitItemKind::Const(ref ty, _) => ty.span,
-                _ => bug!("{:?} is not a trait const", trait_const_item),
-            }
+            let TraitItemKind::Const(ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).kind else { bug!("{trait_const_item:?} is not a trait const") };
+            ty.span
         });
 
         infcx.err_ctxt().note_type_err(
@@ -1795,7 +1760,7 @@ pub(super) fn compare_impl_ty<'tcx>(
 ) {
     debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);
 
-    let _: Result<(), ErrorGuaranteed> = (|| {
+    let _: Result<(), ErrorGuaranteed> = try {
         compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span, false)?;
 
         compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
@@ -1803,8 +1768,8 @@ pub(super) fn compare_impl_ty<'tcx>(
         let sp = tcx.def_span(impl_ty.def_id);
         compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
 
-        check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
-    })();
+        check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)?;
+    };
 }
 
 /// The equivalent of [compare_method_predicate_entailment], but for associated types
@@ -1826,8 +1791,7 @@ fn compare_type_predicate_entailment<'tcx>(
     check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
 
     let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);
-
-    if impl_ty_own_bounds.is_empty() {
+    if impl_ty_own_bounds.len() == 0 {
         // Nothing to check.
         return Ok(());
     }
@@ -1835,20 +1799,22 @@ 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
     // associated type in the trait are assumed.
     let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
     let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
-    hybrid_preds
-        .predicates
-        .extend(trait_ty_predicates.instantiate_own(tcx, trait_to_impl_substs).predicates);
+    hybrid_preds.predicates.extend(
+        trait_ty_predicates
+            .instantiate_own(tcx, trait_to_impl_substs)
+            .map(|(predicate, _)| predicate),
+    );
 
     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,
@@ -1860,15 +1826,13 @@ fn compare_type_predicate_entailment<'tcx>(
 
     debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
 
-    assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
-    for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
-    {
-        let cause = ObligationCause::misc(span, impl_ty_hir_id);
+    for (predicate, span) in impl_ty_own_bounds {
+        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,
@@ -2044,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);
 
@@ -2056,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,
@@ -2068,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
@@ -2099,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 d6e3ddb0a613964238574c6fbc46261d8a00f620..64fd61c1359b599edbd2ae97bb5baae89e6e41b0 100644 (file)
@@ -46,7 +46,7 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
             )
         }
         _ => {
-            // Destructors only work on nominal types.  This was
+            // Destructors only work on nominal types. This was
             // already checked by coherence, but compilation may
             // not have been terminated.
             let span = tcx.def_span(drop_impl_did);
index 598dc2dca5c6288b88eab85e96c9f95d0de8fa1b..955cacf03b1c676f5dfa32fca091b84497f4b825 100644 (file)
@@ -56,8 +56,14 @@ 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);
-        require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id)), fty);
+        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).subst_identity()),
+            fty,
+        );
     }
 }
 
index 17c4d0d482f2ab0b2a72e58c27aad8717f3decff..122b6ead8e9d7f8432a6078cf2b58a318b63db93 100644 (file)
@@ -3,6 +3,7 @@
 use rustc_hir as hir;
 use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
 use rustc_session::lint;
+use rustc_span::def_id::LocalDefId;
 use rustc_span::{Symbol, DUMMY_SP};
 use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType};
 
@@ -253,10 +254,8 @@ fn check_asm_operand_type(
         Some(asm_ty)
     }
 
-    pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: hir::HirId) {
-        let hir = self.tcx.hir();
-        let enclosing_def_id = hir.local_def_id(enclosing_id).to_def_id();
-        let target_features = self.tcx.asm_target_features(enclosing_def_id);
+    pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: LocalDefId) {
+        let target_features = self.tcx.asm_target_features(enclosing_id.to_def_id());
         let Some(asm_arch) = self.tcx.sess.asm_arch else {
             self.tcx.sess.delay_span_bug(DUMMY_SP, "target architecture does not support asm");
             return;
@@ -351,7 +350,7 @@ pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: hir::HirId) {
             }
 
             match *op {
-                hir::InlineAsmOperand::In { reg, ref expr } => {
+                hir::InlineAsmOperand::In { reg, expr } => {
                     self.check_asm_operand_type(
                         idx,
                         reg,
@@ -362,7 +361,7 @@ pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: hir::HirId) {
                         &target_features,
                     );
                 }
-                hir::InlineAsmOperand::Out { reg, late: _, ref expr } => {
+                hir::InlineAsmOperand::Out { reg, late: _, expr } => {
                     if let Some(expr) = expr {
                         self.check_asm_operand_type(
                             idx,
@@ -375,7 +374,7 @@ pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: hir::HirId) {
                         );
                     }
                 }
-                hir::InlineAsmOperand::InOut { reg, late: _, ref expr } => {
+                hir::InlineAsmOperand::InOut { reg, late: _, expr } => {
                     self.check_asm_operand_type(
                         idx,
                         reg,
@@ -386,7 +385,7 @@ pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: hir::HirId) {
                         &target_features,
                     );
                 }
-                hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => {
+                hir::InlineAsmOperand::SplitInOut { reg, late: _, in_expr, out_expr } => {
                     let in_ty = self.check_asm_operand_type(
                         idx,
                         reg,
index 382c3f5294511a40c364060f7b050773bcad737f..bec693439a46c1d26a3ec9ba2753d71d9f75fe64 100644 (file)
 
 - main: the main pass does the lion's share of the work: it
   determines the types of all expressions, resolves
-  methods, checks for most invalid conditions, and so forth.  In
+  methods, checks for most invalid conditions, and so forth. In
   some cases, where a type is unknown, it may create a type or region
   variable and use that as the type of an expression.
 
   In the process of checking, various constraints will be placed on
   these type variables through the subtyping relationships requested
-  through the `demand` module.  The `infer` module is in charge
+  through the `demand` module. The `infer` module is in charge
   of resolving those constraints.
 
 - regionck: after main is complete, the regionck pass goes over all
   types looking for regions and making sure that they did not escape
-  into places where they are not in scope.  This may also influence the
+  into places where they are not in scope. This may also influence the
   final assignments of the various region variables if there is some
   flexibility.
 
 - writeback: writes the final types within a function body, replacing
-  type variables with their final inferred types.  These final types
+  type variables with their final inferred types. These final types
   are written into the `tcx.node_types` table, which should *never* contain
   any reference to a type variable.
 
@@ -38,8 +38,8 @@
 
 While type checking a function, the intermediate types for the
 expressions, blocks, and so forth contained within the function are
-stored in `fcx.node_types` and `fcx.node_substs`.  These types
-may contain unresolved type variables.  After type checking is
+stored in `fcx.node_types` and `fcx.node_substs`. These types
+may contain unresolved type variables. After type checking is
 complete, the functions in the writeback module are used to take the
 types from this table, resolve them, and then write them into their
 permanent home in the type context `tcx`.
 The types of top-level items, which never contain unbound type
 variables, are stored directly into the `tcx` typeck_results.
 
-N.B., a type variable is not the same thing as a type parameter.  A
+N.B., a type variable is not the same thing as a type parameter. A
 type variable is an instance of a type parameter. That is,
 given a generic function `fn foo<T>(t: T)`, while checking the
 function `foo`, the type `ty_param(0)` refers to the type `T`, which
 is treated in abstract. However, when `foo()` is called, `T` will be
-substituted for a fresh type variable `N`.  This variable will
+substituted for a fresh type variable `N`. This variable will
 eventually be resolved to some concrete type (which might itself be
 a type parameter).
 
@@ -105,6 +105,7 @@ pub fn provide(providers: &mut Providers) {
         region_scope_tree,
         collect_return_position_impl_trait_in_trait_tys,
         compare_impl_const: compare_impl_item::compare_impl_const_raw,
+        check_generator_obligations: check::check_generator_obligations,
         ..*providers
     };
 }
@@ -441,11 +442,11 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
         ty::AssocKind::Fn => {
             // We skip the binder here because the binder would deanonymize all
             // late-bound regions, and we don't want method signatures to show up
-            // `as for<'r> fn(&'r MyType)`.  Pretty-printing handles late-bound
+            // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
             // regions just fine, showing `fn(&MyType)`.
             fn_sig_suggestion(
                 tcx,
-                tcx.fn_sig(assoc.def_id).skip_binder(),
+                tcx.fn_sig(assoc.def_id).subst_identity().skip_binder(),
                 assoc.ident(tcx),
                 tcx.predicates_of(assoc.def_id),
                 assoc,
index b315ebad4686c37d4bac86575a991a744e2c27f0..b28bfb1d54b6ca7d1bc256a16b564ffe954a720f 100644 (file)
@@ -180,7 +180,7 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir
 
     visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
 
-    if let Some(hir::Guard::If(ref expr)) = arm.guard {
+    if let Some(hir::Guard::If(expr)) = arm.guard {
         visitor.terminating_scopes.insert(expr.hir_id.local_id);
     }
 
@@ -242,8 +242,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
             // This ensures fixed size stacks.
             hir::ExprKind::Binary(
                 source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
-                ref l,
-                ref r,
+                l,
+                r,
             ) => {
                 // expr is a short circuiting operator (|| or &&). As its
                 // functionality can't be overridden by traits, it always
@@ -288,20 +288,20 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
                     terminating(r.hir_id.local_id);
                 }
             }
-            hir::ExprKind::If(_, ref then, Some(ref otherwise)) => {
+            hir::ExprKind::If(_, then, Some(otherwise)) => {
                 terminating(then.hir_id.local_id);
                 terminating(otherwise.hir_id.local_id);
             }
 
-            hir::ExprKind::If(_, ref then, None) => {
+            hir::ExprKind::If(_, then, None) => {
                 terminating(then.hir_id.local_id);
             }
 
-            hir::ExprKind::Loop(ref body, _, _, _) => {
+            hir::ExprKind::Loop(body, _, _, _) => {
                 terminating(body.hir_id.local_id);
             }
 
-            hir::ExprKind::DropTemps(ref expr) => {
+            hir::ExprKind::DropTemps(expr) => {
                 // `DropTemps(expr)` does not denote a conditional scope.
                 // Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`.
                 terminating(expr.hir_id.local_id);
@@ -325,7 +325,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
                 // The idea is that call.callee_id represents *the time when
                 // the invoked function is actually running* and call.id
                 // represents *the time to prepare the arguments and make the
-                // call*.  See the section "Borrows in Calls" borrowck/README.md
+                // call*. See the section "Borrows in Calls" borrowck/README.md
                 // for an extended explanation of why this distinction is
                 // important.
                 //
@@ -396,7 +396,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
             let body = visitor.tcx.hir().body(body);
             visitor.visit_body(body);
         }
-        hir::ExprKind::AssignOp(_, ref left_expr, ref right_expr) => {
+        hir::ExprKind::AssignOp(_, left_expr, right_expr) => {
             debug!(
                 "resolve_expr - enabling pessimistic_yield, was previously {}",
                 prev_pessimistic
@@ -447,7 +447,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
             }
         }
 
-        hir::ExprKind::If(ref cond, ref then, Some(ref otherwise)) => {
+        hir::ExprKind::If(cond, then, Some(otherwise)) => {
             let expr_cx = visitor.cx;
             visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen });
             visitor.cx.var_parent = visitor.cx.parent;
@@ -457,7 +457,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
             visitor.visit_expr(otherwise);
         }
 
-        hir::ExprKind::If(ref cond, ref then, None) => {
+        hir::ExprKind::If(cond, then, None) => {
             let expr_cx = visitor.cx;
             visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen });
             visitor.cx.var_parent = visitor.cx.parent;
@@ -641,21 +641,21 @@ fn is_binding_pat(pat: &hir::Pat<'_>) -> bool {
         match pat.kind {
             PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes, _), ..) => true,
 
-            PatKind::Struct(_, ref field_pats, _) => {
+            PatKind::Struct(_, field_pats, _) => {
                 field_pats.iter().any(|fp| is_binding_pat(&fp.pat))
             }
 
-            PatKind::Slice(ref pats1, ref pats2, ref pats3) => {
+            PatKind::Slice(pats1, pats2, pats3) => {
                 pats1.iter().any(|p| is_binding_pat(&p))
                     || pats2.iter().any(|p| is_binding_pat(&p))
                     || pats3.iter().any(|p| is_binding_pat(&p))
             }
 
-            PatKind::Or(ref subpats)
-            | PatKind::TupleStruct(_, ref subpats, _)
-            | PatKind::Tuple(ref subpats, _) => subpats.iter().any(|p| is_binding_pat(&p)),
+            PatKind::Or(subpats)
+            | PatKind::TupleStruct(_, subpats, _)
+            | PatKind::Tuple(subpats, _) => subpats.iter().any(|p| is_binding_pat(&p)),
 
-            PatKind::Box(ref subpat) => is_binding_pat(&subpat),
+            PatKind::Box(subpat) => is_binding_pat(&subpat),
 
             PatKind::Ref(_, _)
             | PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..)
@@ -704,11 +704,11 @@ fn record_rvalue_scope_if_borrow_expr<'tcx>(
                     record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
                 }
             }
-            hir::ExprKind::Cast(ref subexpr, _) => {
+            hir::ExprKind::Cast(subexpr, _) => {
                 record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id)
             }
-            hir::ExprKind::Block(ref block, _) => {
-                if let Some(ref subexpr) = block.expr {
+            hir::ExprKind::Block(block, _) => {
+                if let Some(subexpr) = block.expr {
                     record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
                 }
             }
index 92fd4625ee83574dbe515e06928cfe2373b5878a..67bcfb1cb70fc0c32605101035fc35fdfdcde64c 100644 (file)
 };
 
 use std::cell::LazyCell;
-use std::iter;
 use std::ops::{ControlFlow, Deref};
 
 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> {
@@ -60,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,
         )
@@ -72,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(
@@ -94,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()
@@ -106,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() {
@@ -179,10 +180,10 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
         //
         // won't be allowed unless there's an *explicit* implementation of `Send`
         // for `T`
-        hir::ItemKind::Impl(ref impl_) => {
+        hir::ItemKind::Impl(impl_) => {
             let is_auto = tcx
                 .impl_trait_ref(def_id)
-                .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
+                .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id));
             if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
                 let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
                 let mut err =
@@ -225,15 +226,15 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
         hir::ItemKind::Const(ty, ..) => {
             check_item_type(tcx, def_id, ty.span, false);
         }
-        hir::ItemKind::Struct(_, ref ast_generics) => {
+        hir::ItemKind::Struct(_, ast_generics) => {
             check_type_defn(tcx, item, false);
             check_variances_for_type_defn(tcx, item, ast_generics);
         }
-        hir::ItemKind::Union(_, ref ast_generics) => {
+        hir::ItemKind::Union(_, ast_generics) => {
             check_type_defn(tcx, item, true);
             check_variances_for_type_defn(tcx, item, ast_generics);
         }
-        hir::ItemKind::Enum(_, ref ast_generics) => {
+        hir::ItemKind::Enum(_, ast_generics) => {
             check_type_defn(tcx, item, true);
             check_variances_for_type_defn(tcx, item, ast_generics);
         }
@@ -375,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 {
@@ -386,12 +386,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
                         // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
                         let sig: ty::FnSig<'_> = tcx.liberate_late_bound_regions(
                             item_def_id.to_def_id(),
-                            tcx.fn_sig(item_def_id),
+                            tcx.fn_sig(item_def_id).subst_identity(),
                         );
                         gather_gat_bounds(
                             tcx,
                             param_env,
-                            item_hir_id,
+                            item_def_id,
                             sig.inputs_and_output,
                             // We also assume that all of the function signature's parameter types
                             // are well formed.
@@ -413,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,
                             tcx.explicit_item_bounds(item_def_id).to_vec(),
                             &FxIndexSet::default(),
                             gat_def_id.def_id,
@@ -459,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()
@@ -467,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())
@@ -552,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: hir::OwnerId,
     to_check: T,
     wf_tys: &FxIndexSet<Ty<'tcx>>,
     gat_def_id: LocalDefId,
@@ -585,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.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
@@ -623,7 +634,14 @@ 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.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.
@@ -659,7 +677,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>,
@@ -676,7 +694,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>,
@@ -700,7 +718,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>),
@@ -823,7 +841,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
         _ => {}
     }
     if !trait_should_be_self.is_empty() {
-        if tcx.object_safety_violations(trait_def_id).is_empty() {
+        if tcx.check_is_object_safe(trait_def_id) {
             return;
         }
         let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect();
@@ -1007,7 +1025,7 @@ fn check_associated_item(
                 wfcx.register_wf_obligation(span, loc, ty.into());
             }
             ty::AssocKind::Fn => {
-                let sig = tcx.fn_sig(item.def_id);
+                let sig = tcx.fn_sig(item.def_id).subst_identity();
                 let hir_sig = sig_if_method.expect("bad signature for method");
                 check_fn_or_method(
                     wfcx,
@@ -1094,7 +1112,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,
@@ -1114,7 +1132,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(
@@ -1175,7 +1193,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,
         )
@@ -1192,7 +1210,7 @@ fn check_item_fn(
     decl: &hir::FnDecl<'_>,
 ) {
     enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| {
-        let sig = tcx.fn_sig(def_id);
+        let sig = tcx.fn_sig(def_id).subst_identity();
         check_fn_or_method(wfcx, ident.span, sig, decl, def_id);
     })
 }
@@ -1215,7 +1233,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),
@@ -1230,7 +1248,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)),
@@ -1248,12 +1266,12 @@ fn check_impl<'tcx>(
     constness: hir::Constness,
 ) {
     enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
-        match *ast_trait_ref {
-            Some(ref ast_trait_ref) => {
+        match ast_trait_ref {
+            Some(ast_trait_ref) => {
                 // `#[rustc_reservation_impl]` impls are not real impls and
                 // therefore don't need to be WF (the trait's `Self: Trait` predicate
                 // won't hold).
-                let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap();
+                let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().subst_identity();
                 let trait_ref = wfcx.normalize(
                     ast_trait_ref.path.span,
                     Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
@@ -1270,7 +1288,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,
@@ -1310,7 +1328,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
     let infcx = wfcx.infcx;
     let tcx = wfcx.tcx();
 
-    let predicates = tcx.bound_predicates_of(def_id.to_def_id());
+    let predicates = tcx.predicates_of(def_id.to_def_id());
     let generics = tcx.generics_of(def_id);
 
     let is_our_default = |def: &ty::GenericParamDef| match def.kind {
@@ -1350,7 +1368,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
                     // is incorrect when dealing with unused substs, for example
                     // for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
                     // we should eagerly error.
-                    let default_ct = tcx.const_param_default(param.def_id);
+                    let default_ct = tcx.const_param_default(param.def_id).subst_identity();
                     if !default_ct.needs_subst() {
                         wfcx.register_wf_obligation(
                             tcx.def_span(param.def_id),
@@ -1396,7 +1414,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
             GenericParamDefKind::Const { .. } => {
                 // If the param has a default, ...
                 if is_our_default(param) {
-                    let default_ct = tcx.const_param_default(param.def_id);
+                    let default_ct = tcx.const_param_default(param.def_id).subst_identity();
                     // ... and it's not a dependent default, ...
                     if !default_ct.needs_subst() {
                         // ... then substitute it with the default.
@@ -1411,7 +1429,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
 
     // Now we build the substituted predicates.
     let default_obligations = predicates
-        .0
         .predicates
         .iter()
         .flat_map(|&(pred, sp)| {
@@ -1430,7 +1447,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 }
 
                 fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-                    ControlFlow::BREAK
+                    ControlFlow::Break(())
                 }
 
                 fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -1442,13 +1459,13 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
             let mut param_count = CountParams::default();
             let has_region = pred.visit_with(&mut param_count).is_break();
-            let substituted_pred = predicates.rebind(pred).subst(tcx, substs);
+            let substituted_pred = ty::EarlyBinder(pred).subst(tcx, substs);
             // Don't check non-defaulted params, dependent defaults (including lifetimes)
             // or preds with multiple params.
             if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region
             {
                 None
-            } else if predicates.0.predicates.iter().any(|&(p, _)| p == substituted_pred) {
+            } else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) {
                 // Avoid duplication of predicates that contain no parameters, for example.
                 None
             } else {
@@ -1468,29 +1485,27 @@ 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)
         });
 
-    let predicates = predicates.0.instantiate_identity(tcx);
+    let predicates = predicates.instantiate_identity(tcx);
 
     let predicates = wfcx.normalize(span, None, predicates);
 
     debug!(?predicates.predicates);
     assert_eq!(predicates.predicates.len(), predicates.spans.len());
-    let wf_obligations =
-        iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| {
-            traits::wf::predicate_obligations(
-                infcx,
-                wfcx.param_env.without_const(),
-                wfcx.body_id,
-                p,
-                sp,
-            )
-        });
-
+    let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| {
+        traits::wf::predicate_obligations(
+            infcx,
+            wfcx.param_env.without_const(),
+            wfcx.body_def_id,
+            p,
+            sp,
+        )
+    });
     let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect();
     wfcx.register_obligations(obligations);
 }
@@ -1552,7 +1567,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)),
@@ -1600,7 +1615,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,
                     )
@@ -1630,7 +1645,7 @@ fn check_method_receiver<'tcx>(
 
     let span = fn_sig.decl.inputs[0].span;
 
-    let sig = tcx.fn_sig(method.def_id);
+    let sig = tcx.fn_sig(method.def_id).subst_identity();
     let sig = tcx.liberate_late_bound_regions(method.def_id, sig);
     let sig = wfcx.normalize(span, None, sig);
 
@@ -1700,7 +1715,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();
 
@@ -1712,7 +1727,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 {
@@ -1897,8 +1912,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);
 
@@ -1913,7 +1927,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)
 
@@ -1932,7 +1946,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 5749b04783ce4ff8c7608e83771a3754471fffe4..ebb78213a63a13dd052f0b3b4e7c48f5c5acc451 100644 (file)
@@ -50,7 +50,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
 fn unused_crates_lint(tcx: TyCtxt<'_>) {
     let lint = lint::builtin::UNUSED_EXTERN_CRATES;
 
-    // Collect first the crates that are completely unused.  These we
+    // Collect first the crates that are completely unused. These we
     // can always suggest removing (no matter which edition we are
     // in).
     let unused_extern_crates: FxHashMap<LocalDefId, Span> = tcx
index 2e2c1591e9b4472dffb5e39a22b33b92685fbbc7..76668f7e9ac4b0379a5ff9db80e6a20ebe42e003 100644 (file)
@@ -7,13 +7,15 @@
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::ItemKind;
-use rustc_infer::infer;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{self, RegionResolutionError};
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
 use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable};
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
-use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
+use rustc_trait_selection::traits::misc::{
+    type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason,
+};
 use rustc_trait_selection::traits::predicate_for_trait_def;
 use rustc_trait_selection::traits::{self, ObligationCause};
 use std::collections::BTreeMap;
@@ -54,19 +56,14 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
         _ => {}
     }
 
-    let sp = match tcx.hir().expect_item(impl_did).kind {
-        ItemKind::Impl(ref impl_) => impl_.self_ty.span,
-        _ => bug!("expected Drop impl item"),
-    };
+    let ItemKind::Impl(impl_) = tcx.hir().expect_item(impl_did).kind else { bug!("expected Drop impl item") };
 
-    tcx.sess.emit_err(DropImplOnWrongItem { span: sp });
+    tcx.sess.emit_err(DropImplOnWrongItem { span: impl_.self_ty.span });
 }
 
 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);
 
@@ -81,8 +78,8 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
         _ => bug!("expected Copy impl item"),
     };
 
-    let cause = traits::ObligationCause::misc(span, impl_hir_id);
-    match can_type_implement_copy(tcx, param_env, self_type, cause) {
+    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)) => {
             let mut err = struct_span_err!(
@@ -97,50 +94,70 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
             let mut errors: BTreeMap<_, Vec<_>> = Default::default();
             let mut bounds = vec![];
 
-            for (field, ty) in fields {
+            for (field, ty, reason) in fields {
                 let field_span = tcx.def_span(field.did);
-                let field_ty_span = match tcx.hir().get_if_local(field.did) {
-                    Some(hir::Node::Field(field_def)) => field_def.ty.span,
-                    _ => field_span,
-                };
                 err.span_label(field_span, "this field does not implement `Copy`");
-                // Spin up a new FulfillmentContext, so we can get the _precise_ reason
-                // why this field does not implement Copy. This is useful because sometimes
-                // it is not immediately clear why Copy is not implemented for a field, since
-                // all we point at is the field itself.
-                let infcx = tcx.infer_ctxt().ignoring_regions().build();
-                for error in traits::fully_solve_bound(
-                    &infcx,
-                    traits::ObligationCause::dummy_with_span(field_ty_span),
-                    param_env,
-                    ty,
-                    tcx.require_lang_item(LangItem::Copy, Some(span)),
-                ) {
-                    let error_predicate = error.obligation.predicate;
-                    // Only note if it's not the root obligation, otherwise it's trivial and
-                    // should be self-explanatory (i.e. a field literally doesn't implement Copy).
-
-                    // FIXME: This error could be more descriptive, especially if the error_predicate
-                    // contains a foreign type or if it's a deeply nested type...
-                    if error_predicate != error.root_obligation.predicate {
-                        errors
-                            .entry((ty.to_string(), error_predicate.to_string()))
-                            .or_default()
-                            .push(error.obligation.cause.span);
+
+                match reason {
+                    InfringingFieldsReason::Fulfill(fulfillment_errors) => {
+                        for error in fulfillment_errors {
+                            let error_predicate = error.obligation.predicate;
+                            // Only note if it's not the root obligation, otherwise it's trivial and
+                            // should be self-explanatory (i.e. a field literally doesn't implement Copy).
+
+                            // FIXME: This error could be more descriptive, especially if the error_predicate
+                            // contains a foreign type or if it's a deeply nested type...
+                            if error_predicate != error.root_obligation.predicate {
+                                errors
+                                    .entry((ty.to_string(), error_predicate.to_string()))
+                                    .or_default()
+                                    .push(error.obligation.cause.span);
+                            }
+                            if let ty::PredicateKind::Clause(ty::Clause::Trait(
+                                ty::TraitPredicate {
+                                    trait_ref,
+                                    polarity: ty::ImplPolarity::Positive,
+                                    ..
+                                },
+                            )) = error_predicate.kind().skip_binder()
+                            {
+                                let ty = trait_ref.self_ty();
+                                if let ty::Param(_) = ty.kind() {
+                                    bounds.push((
+                                        format!("{ty}"),
+                                        trait_ref.print_only_trait_path().to_string(),
+                                        Some(trait_ref.def_id),
+                                    ));
+                                }
+                            }
+                        }
                     }
-                    if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
-                        trait_ref,
-                        polarity: ty::ImplPolarity::Positive,
-                        ..
-                    })) = error_predicate.kind().skip_binder()
-                    {
-                        let ty = trait_ref.self_ty();
-                        if let ty::Param(_) = ty.kind() {
-                            bounds.push((
-                                format!("{ty}"),
-                                trait_ref.print_only_trait_path().to_string(),
-                                Some(trait_ref.def_id),
-                            ));
+                    InfringingFieldsReason::Regions(region_errors) => {
+                        for error in region_errors {
+                            let ty = ty.to_string();
+                            match error {
+                                RegionResolutionError::ConcreteFailure(origin, a, b) => {
+                                    let predicate = format!("{b}: {a}");
+                                    errors
+                                        .entry((ty.clone(), predicate.clone()))
+                                        .or_default()
+                                        .push(origin.span());
+                                    if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
+                                        bounds.push((b.to_string(), a.to_string(), None));
+                                    }
+                                }
+                                RegionResolutionError::GenericBoundFailure(origin, a, b) => {
+                                    let predicate = format!("{a}: {b}");
+                                    errors
+                                        .entry((ty.clone(), predicate.clone()))
+                                        .or_default()
+                                        .push(origin.span());
+                                    if let infer::region_constraints::GenericKind::Param(_) = a {
+                                        bounds.push((a.to_string(), b.to_string(), None));
+                                    }
+                                }
+                                _ => continue,
+                            }
                         }
                     }
                 }
@@ -192,7 +209,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
     let source = tcx.type_of(impl_did);
     assert!(!source.has_escaping_bound_vars());
     let target = {
-        let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+        let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
         assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
 
         trait_ref.substs.type_at(1)
@@ -205,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()) {
@@ -354,7 +371,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
     });
 
     let source = tcx.type_of(impl_did);
-    let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+    let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
     assert_eq!(trait_ref.def_id, coerce_unsized_trait);
     let target = trait_ref.substs.type_at(1);
     debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
@@ -367,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>| {
@@ -438,7 +454,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
             // when this coercion occurs, we would be changing the
             // field `ptr` from a thin pointer of type `*mut [i32;
             // 3]` to a fat pointer of type `*mut [i32]` (with
-            // extra data `3`).  **The purpose of this check is to
+            // extra data `3`). **The purpose of this check is to
             // make sure that we know how to do this conversion.**
             //
             // To check if this impl is legal, we would walk down
@@ -505,12 +521,11 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
                 return err_info;
             } else if diff_fields.len() > 1 {
                 let item = tcx.hir().expect_item(impl_did);
-                let span =
-                    if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) = item.kind {
-                        t.path.span
-                    } else {
-                        tcx.def_span(impl_did)
-                    };
+                let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
+                    t.path.span
+                } else {
+                    tcx.def_span(impl_did)
+                };
 
                 struct_span_err!(
                     tcx.sess,
@@ -557,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 6469f389bf91b313141ce01452fe74cb68b72f98..c1b0237b2d1f13813c9ccd195d60441e532b4ea2 100644 (file)
@@ -182,7 +182,7 @@ fn check_item(&mut self, id: hir::ItemId) {
         }
 
         let item = self.tcx.hir().item(id);
-        let hir::ItemKind::Impl(hir::Impl { of_trait: None, self_ty: ty, ref items, .. }) = item.kind else {
+        let hir::ItemKind::Impl(hir::Impl { of_trait: None, self_ty: ty, items, .. }) = item.kind else {
             return;
         };
 
@@ -240,6 +240,7 @@ fn check_item(&mut self, id: hir::ItemId) {
             | ty::Closure(..)
             | ty::Generator(..)
             | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..)
             | ty::Bound(..)
             | ty::Placeholder(_)
             | ty::Infer(_) => {
index 1bf3768fead3619f9fb5781cb8f9314c21f6e256..bbde59c953a026375ef708e93141d0691d3fd2c5 100644 (file)
@@ -128,7 +128,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) {
 
     let impls = tcx.hir().trait_impls(def_id);
     for &impl_def_id in impls {
-        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
 
         check_impl(tcx, impl_def_id, trait_ref);
         check_object_overlap(tcx, impl_def_id, trait_ref);
@@ -169,9 +169,9 @@ fn check_object_overlap<'tcx>(
         });
 
         for component_def_id in component_def_ids {
-            if !tcx.is_object_safe(component_def_id) {
+            if !tcx.check_is_object_safe(component_def_id) {
                 // Without the 'object_safe_for_dispatch' feature this is an error
-                // which will be reported by wfcheck.  Ignore it here.
+                // which will be reported by wfcheck. Ignore it here.
                 // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
                 // With the feature enabled, the trait is not implemented automatically,
                 // so this is valid.
index e8b3f139623ed56ce750a81dc1a6765f0fc2fd62..95b03eb8263fda2031504dd4ef6a22319b31b23a 100644 (file)
@@ -21,7 +21,7 @@ pub(crate) fn orphan_check_impl(
     tcx: TyCtxt<'_>,
     impl_def_id: LocalDefId,
 ) -> Result<(), ErrorGuaranteed> {
-    let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+    let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
     trait_ref.error_reported()?;
 
     let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id);
@@ -40,7 +40,7 @@ fn do_orphan_check_impl<'tcx>(
     let trait_def_id = trait_ref.def_id;
 
     let item = tcx.hir().expect_item(def_id);
-    let hir::ItemKind::Impl(ref impl_) = item.kind else {
+    let hir::ItemKind::Impl(impl_) = item.kind else {
         bug!("{:?} is not an impl: {:?}", def_id, item);
     };
     let sp = tcx.def_span(def_id);
@@ -416,13 +416,13 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             if t != self.self_ty_root {
                 for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) {
                     match tcx.impl_polarity(impl_def_id) {
-                        ImplPolarity::Negative => return ControlFlow::BREAK,
+                        ImplPolarity::Negative => return ControlFlow::Break(()),
                         ImplPolarity::Reservation => {}
                         // FIXME(@lcnr): That's probably not good enough, idk
                         //
                         // We might just want to take the rustdoc code and somehow avoid
                         // explicit impls for `Self`.
-                        ImplPolarity::Positive => return ControlFlow::CONTINUE,
+                        ImplPolarity::Positive => return ControlFlow::Continue(()),
                     }
                 }
             }
@@ -440,7 +440,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                         }
                     }
 
-                    ControlFlow::CONTINUE
+                    ControlFlow::Continue(())
                 }
                 _ => t.super_visit_with(self),
             }
index 70cc15b2f8c543268f926a32ff79ea330acce294..fe6119dce873573baf819591798c33e3ecc19b92 100644 (file)
 pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl));
     let item = tcx.hir().expect_item(def_id);
-    let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() };
+    let hir::ItemKind::Impl(impl_) = item.kind else { bug!() };
 
     if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
+        let trait_ref = trait_ref.subst_identity();
         let trait_def = tcx.trait_def(trait_ref.def_id);
         let unsafe_attr =
             impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
index cd745ee8cab69929e714c78fa546108a30b8ca1e..f5a1e51c07b2f53edecc49e633318789dfeb08fd 100644 (file)
@@ -25,7 +25,7 @@
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericParamKind, Node};
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::query::Providers;
@@ -76,6 +76,7 @@ pub fn provide(providers: &mut Providers) {
         is_foreign_item,
         generator_kind,
         collect_mod_item_types,
+        is_type_alias_impl_trait,
         ..*providers
     };
 }
@@ -516,6 +517,10 @@ fn set_tainted_by_errors(&self, _: ErrorGuaranteed) {
     fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
         // There's no place to record types from signatures?
     }
+
+    fn infcx(&self) -> Option<&InferCtxt<'tcx>> {
+        None
+    }
 }
 
 /// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.
@@ -560,7 +565,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
     debug!("convert: item {} with id {}", it.ident, it.hir_id());
     let def_id = item_id.owner_id.def_id;
 
-    match it.kind {
+    match &it.kind {
         // These don't define types.
         hir::ItemKind::ExternCrate(_)
         | hir::ItemKind::Use(..)
@@ -568,7 +573,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
         | hir::ItemKind::Mod(_)
         | hir::ItemKind::GlobalAsm(_) => {}
         hir::ItemKind::ForeignMod { items, .. } => {
-            for item in items {
+            for item in *items {
                 let item = tcx.hir().foreign_item(item.id);
                 tcx.ensure().generics_of(item.owner_id);
                 tcx.ensure().type_of(item.owner_id);
@@ -618,7 +623,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             tcx.at(it.span).super_predicates_of(def_id);
             tcx.ensure().predicates_of(def_id);
         }
-        hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
+        hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => {
             tcx.ensure().generics_of(def_id);
             tcx.ensure().type_of(def_id);
             tcx.ensure().predicates_of(def_id);
@@ -853,14 +858,14 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> {
     };
 
     let repr = tcx.repr_options_of_def(def_id.to_def_id());
-    let (kind, variants) = match item.kind {
-        ItemKind::Enum(ref def, _) => {
+    let (kind, variants) = match &item.kind {
+        ItemKind::Enum(def, _) => {
             let mut distance_from_explicit = 0;
             let variants = def
                 .variants
                 .iter()
                 .map(|v| {
-                    let discr = if let Some(ref e) = v.disr_expr {
+                    let discr = if let Some(e) = &v.disr_expr {
                         distance_from_explicit = 0;
                         ty::VariantDiscr::Explicit(e.def_id.to_def_id())
                     } else {
@@ -882,7 +887,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> {
 
             (AdtKind::Enum, variants)
         }
-        ItemKind::Struct(ref def, _) | ItemKind::Union(ref def, _) => {
+        ItemKind::Struct(def, _) | ItemKind::Union(def, _) => {
             let adt_kind = match item.kind {
                 ItemKind::Struct(..) => AdtKind::Struct,
                 _ => AdtKind::Union,
@@ -1086,7 +1091,7 @@ pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir
 }
 
 #[instrument(level = "debug", skip(tcx))]
-fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
+fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> {
     use rustc_hir::Node::*;
     use rustc_hir::*;
 
@@ -1095,7 +1100,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
 
     let icx = ItemCtxt::new(tcx, def_id.to_def_id());
 
-    match tcx.hir().get(hir_id) {
+    let output = match tcx.hir().get(hir_id) {
         TraitItem(hir::TraitItem {
             kind: TraitItemKind::Fn(sig, TraitFn::Provided(_)),
             generics,
@@ -1168,7 +1173,8 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
         x => {
             bug!("unexpected sort of node in fn_sig(): {:?}", x);
         }
-    }
+    };
+    ty::EarlyBinder(output)
 }
 
 fn infer_return_ty_for_fn_sig<'tcx>(
@@ -1247,11 +1253,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(_, _, _, _, _) -> _ =
@@ -1323,7 +1330,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),
         );
@@ -1339,20 +1346,22 @@ fn suggest_impl_trait<'tcx>(
     None
 }
 
-fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
+fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> {
     let icx = ItemCtxt::new(tcx, def_id);
     let item = tcx.hir().expect_item(def_id.expect_local());
-    match item.kind {
-        hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
+    let hir::ItemKind::Impl(impl_) = item.kind else { bug!() };
+    impl_
+        .of_trait
+        .as_ref()
+        .map(|ast_trait_ref| {
             let selfty = tcx.type_of(def_id);
             icx.astconv().instantiate_mono_trait_ref(
                 ast_trait_ref,
                 selfty,
                 check_impl_constness(tcx, impl_.constness, ast_trait_ref),
             )
-        }),
-        _ => bug!(),
-    }
+        })
+        .map(ty::EarlyBinder)
 }
 
 fn check_impl_constness(
@@ -1507,7 +1516,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
         for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) {
             check(input, *ty)
         }
-        if let hir::FnRetTy::Return(ref ty) = decl.output {
+        if let hir::FnRetTy::Return(ty) = decl.output {
             check(ty, fty.output().skip_binder())
         }
     }
@@ -1533,3 +1542,13 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind>
         _ => bug!("generator_kind applied to non-local def-id {:?}", def_id),
     }
 }
+
+fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
+    match tcx.hir().get_if_local(def_id) {
+        Some(Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. })) => {
+            matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias)
+        }
+        Some(_) => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
+        _ => bug!("tried getting opaque_ty_origin for non-local def-id {:?}", def_id),
+    }
+}
index 9a5f447c260f54d8a835ac20fe791f244eb1624e..014ee9fcc207b425b06bac78729f606d2fbc6ebd 100644 (file)
@@ -110,12 +110,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                     // expressions' count (i.e. `N` in `[x; N]`), and explicit
                     // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
                     // as they shouldn't be able to cause query cycle errors.
-                    Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
+                    Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
                         if constant.hir_id() == hir_id =>
                     {
                         Some(parent_def_id.to_def_id())
                     }
-                    Node::Variant(Variant { disr_expr: Some(ref constant), .. })
+                    Node::Variant(Variant { disr_expr: Some(constant), .. })
                         if constant.hir_id == hir_id =>
                     {
                         Some(parent_def_id.to_def_id())
@@ -259,7 +259,7 @@ enum Defaults {
 
     params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
         GenericParamKind::Lifetime { .. } => None,
-        GenericParamKind::Type { ref default, synthetic, .. } => {
+        GenericParamKind::Type { default, synthetic, .. } => {
             if default.is_some() {
                 match allow_defaults {
                     Defaults::Allowed => {}
@@ -426,26 +426,22 @@ fn has_late_bound_regions<'tcx>(
     }
 
     match node {
-        Node::TraitItem(item) => match item.kind {
-            hir::TraitItemKind::Fn(ref sig, _) => {
-                has_late_bound_regions(tcx, &item.generics, sig.decl)
-            }
+        Node::TraitItem(item) => match &item.kind {
+            hir::TraitItemKind::Fn(sig, _) => has_late_bound_regions(tcx, &item.generics, sig.decl),
             _ => None,
         },
-        Node::ImplItem(item) => match item.kind {
-            hir::ImplItemKind::Fn(ref sig, _) => {
-                has_late_bound_regions(tcx, &item.generics, sig.decl)
-            }
+        Node::ImplItem(item) => match &item.kind {
+            hir::ImplItemKind::Fn(sig, _) => has_late_bound_regions(tcx, &item.generics, sig.decl),
             _ => None,
         },
         Node::ForeignItem(item) => match item.kind {
-            hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
+            hir::ForeignItemKind::Fn(fn_decl, _, generics) => {
                 has_late_bound_regions(tcx, generics, fn_decl)
             }
             _ => None,
         },
-        Node::Item(item) => match item.kind {
-            hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
+        Node::Item(item) => match &item.kind {
+            hir::ItemKind::Fn(sig, .., generics, _) => {
                 has_late_bound_regions(tcx, generics, sig.decl)
             }
             _ => None,
index 62eef710ba48f0542079996933b500f5b5643304..8d479f1c3e335f37e6b6d8dab2d5fdf083055d8a 100644 (file)
@@ -99,12 +99,16 @@ pub(super) fn explicit_item_bounds(
     }
 }
 
-pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> {
-    tcx.mk_predicates(
+pub(super) fn item_bounds(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> {
+    let bounds = tcx.mk_predicates(
         util::elaborate_predicates(
             tcx,
             tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
         )
         .map(|obligation| obligation.predicate),
-    )
+    );
+    ty::EarlyBinder(bounds)
 }
index 35f10dc873745f59d4355f1ebe675890f468f0b7..3c67722b637bfa93aa9c33d5c0a3ea1955c2dbf5 100644 (file)
@@ -1,9 +1,9 @@
 //! Resolution of early vs late bound lifetimes.
 //!
-//! Name resolution for lifetimes is performed on the AST and embedded into HIR.  From this
+//! Name resolution for lifetimes is performed on the AST and embedded into HIR. From this
 //! information, typechecking needs to transform the lifetime parameters into bound lifetimes.
-//! Lifetimes can be early-bound or late-bound.  Construction of typechecking terms needs to visit
-//! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices.  This file
+//! Lifetimes can be early-bound or late-bound. Construction of typechecking terms needs to visit
+//! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file
 //! is also responsible for assigning their semantics to implicit lifetimes in trait objects.
 
 use rustc_ast::walk_list;
@@ -70,7 +70,7 @@ fn shifted(self, amount: u32) -> Region {
 /// that it corresponds to.
 ///
 /// FIXME. This struct gets converted to a `ResolveLifetimes` for
-/// actual use. It has the same data, but indexed by `LocalDefId`.  This
+/// actual use. It has the same data, but indexed by `LocalDefId`. This
 /// is silly.
 #[derive(Debug, Default)]
 struct NamedRegionMap {
@@ -428,7 +428,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             _ => {}
         }
         match item.kind {
-            hir::ItemKind::Fn(_, ref generics, _) => {
+            hir::ItemKind::Fn(_, generics, _) => {
                 self.visit_early_late(item.hir_id(), generics, |this| {
                     intravisit::walk_item(this, item);
                 });
@@ -508,13 +508,13 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     this.with(scope, |this| intravisit::walk_item(this, item))
                 });
             }
-            hir::ItemKind::TyAlias(_, ref generics)
-            | hir::ItemKind::Enum(_, ref generics)
-            | hir::ItemKind::Struct(_, ref generics)
-            | hir::ItemKind::Union(_, ref generics)
-            | hir::ItemKind::Trait(_, _, ref generics, ..)
-            | hir::ItemKind::TraitAlias(ref generics, ..)
-            | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
+            hir::ItemKind::TyAlias(_, generics)
+            | hir::ItemKind::Enum(_, generics)
+            | hir::ItemKind::Struct(_, generics)
+            | hir::ItemKind::Union(_, generics)
+            | hir::ItemKind::Trait(_, _, generics, ..)
+            | hir::ItemKind::TraitAlias(generics, ..)
+            | hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
                 // These kinds of items have only early-bound lifetime parameters.
                 let lifetimes = generics
                     .params
@@ -544,7 +544,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
 
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
         match item.kind {
-            hir::ForeignItemKind::Fn(_, _, ref generics) => {
+            hir::ForeignItemKind::Fn(_, _, generics) => {
                 self.visit_early_late(item.hir_id(), generics, |this| {
                     intravisit::walk_foreign_item(this, item);
                 })
@@ -561,7 +561,7 @@ fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
     #[instrument(level = "debug", skip(self))]
     fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
         match ty.kind {
-            hir::TyKind::BareFn(ref c) => {
+            hir::TyKind::BareFn(c) => {
                 let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
                     .generic_params
                     .iter()
@@ -587,7 +587,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     intravisit::walk_ty(this, ty);
                 });
             }
-            hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
+            hir::TyKind::TraitObject(bounds, lifetime, _) => {
                 debug!(?bounds, ?lifetime, "TraitObject");
                 let scope = Scope::TraitRefBoundary { s: self.scope };
                 self.with(scope, |this| {
@@ -617,7 +617,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     LifetimeName::Error => {}
                 }
             }
-            hir::TyKind::Ref(ref lifetime_ref, ref mt) => {
+            hir::TyKind::Ref(lifetime_ref, ref mt) => {
                 self.visit_lifetime(lifetime_ref);
                 let scope = Scope::ObjectLifetimeDefault {
                     lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(),
@@ -632,7 +632,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                 //                 ^                  ^ this gets resolved in the scope of
                 //                                      the opaque_ty generics
                 let opaque_ty = self.tcx.hir().item(item_id);
-                match opaque_ty.kind {
+                match &opaque_ty.kind {
                     hir::ItemKind::OpaqueTy(hir::OpaqueTy {
                         origin: hir::OpaqueTyOrigin::TyAlias,
                         ..
@@ -655,7 +655,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                         origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
                         ..
                     }) => {}
-                    ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
+                    i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
                 };
 
                 // Resolve the lifetimes that are applied to the opaque type.
@@ -720,7 +720,7 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
                     intravisit::walk_trait_item(this, trait_item)
                 });
             }
-            Type(bounds, ref ty) => {
+            Type(bounds, ty) => {
                 let generics = &trait_item.generics;
                 let lifetimes = generics
                     .params
@@ -766,7 +766,7 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
             Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| {
                 intravisit::walk_impl_item(this, impl_item)
             }),
-            Type(ref ty) => {
+            Type(ty) => {
                 let generics = &impl_item.generics;
                 let lifetimes: FxIndexMap<LocalDefId, Region> = generics
                     .params
@@ -817,7 +817,7 @@ fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
     fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
         for (i, segment) in path.segments.iter().enumerate() {
             let depth = path.segments.len() - i - 1;
-            if let Some(ref args) = segment.args {
+            if let Some(args) = segment.args {
                 self.visit_segment_args(path.res, depth, args);
             }
         }
@@ -829,11 +829,11 @@ fn visit_fn(
         fd: &'tcx hir::FnDecl<'tcx>,
         body_id: hir::BodyId,
         _: Span,
-        _: hir::HirId,
+        _: LocalDefId,
     ) {
         let output = match fd.output {
             hir::FnRetTy::DefaultReturn(_) => None,
-            hir::FnRetTy::Return(ref ty) => Some(&**ty),
+            hir::FnRetTy::Return(ty) => Some(ty),
         };
         self.visit_fn_like_elision(&fd.inputs, output, matches!(fk, intravisit::FnKind::Closure));
         intravisit::walk_fn_kind(self, fk);
@@ -846,13 +846,13 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
             for param in generics.params {
                 match param.kind {
                     GenericParamKind::Lifetime { .. } => {}
-                    GenericParamKind::Type { ref default, .. } => {
-                        if let Some(ref ty) = default {
-                            this.visit_ty(&ty);
+                    GenericParamKind::Type { default, .. } => {
+                        if let Some(ty) = default {
+                            this.visit_ty(ty);
                         }
                     }
-                    GenericParamKind::Const { ref ty, default } => {
-                        this.visit_ty(&ty);
+                    GenericParamKind::Const { ty, default } => {
+                        this.visit_ty(ty);
                         if let Some(default) = default {
                             this.visit_body(this.tcx.hir().body(default.body));
                         }
@@ -863,9 +863,9 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                 match predicate {
                     &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
                         hir_id,
-                        ref bounded_ty,
+                        bounded_ty,
                         bounds,
-                        ref bound_generic_params,
+                        bound_generic_params,
                         origin,
                         ..
                     }) => {
@@ -905,7 +905,7 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                         })
                     }
                     &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
-                        ref lifetime,
+                        lifetime,
                         bounds,
                         ..
                     }) => {
@@ -914,7 +914,7 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
 
                         if lifetime.res != hir::LifetimeName::Static {
                             for bound in bounds {
-                                let hir::GenericBound::Outlives(ref lt) = bound else {
+                                let hir::GenericBound::Outlives(lt) = bound else {
                                     continue;
                                 };
                                 if lt.res != hir::LifetimeName::Static {
@@ -939,8 +939,8 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                         }
                     }
                     &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
-                        ref lhs_ty,
-                        ref rhs_ty,
+                        lhs_ty,
+                        rhs_ty,
                         ..
                     }) => {
                         this.visit_ty(lhs_ty);
@@ -1042,7 +1042,7 @@ fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifeti
                 }
 
                 for bound in bound.bounds {
-                    if let hir::GenericBound::Outlives(ref lifetime) = *bound {
+                    if let hir::GenericBound::Outlives(lifetime) = bound {
                         set.insert(lifetime.res);
                     }
                 }
@@ -1264,14 +1264,21 @@ fn resolve_lifetime_ref(
             } else if let Some(body_id) = outermost_body {
                 let fn_id = self.tcx.hir().body_owner(body_id);
                 match self.tcx.hir().get(fn_id) {
-                    Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
+                    Node::Item(hir::Item { owner_id, kind: hir::ItemKind::Fn(..), .. })
                     | Node::TraitItem(hir::TraitItem {
-                        kind: hir::TraitItemKind::Fn(..), ..
+                        owner_id,
+                        kind: hir::TraitItemKind::Fn(..),
+                        ..
                     })
-                    | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. })
-                    | Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
-                        let scope = self.tcx.hir().local_def_id(fn_id);
-                        def = Region::Free(scope.to_def_id(), def.id().unwrap());
+                    | Node::ImplItem(hir::ImplItem {
+                        owner_id,
+                        kind: hir::ImplItemKind::Fn(..),
+                        ..
+                    }) => {
+                        def = Region::Free(owner_id.to_def_id(), def.id().unwrap());
+                    }
+                    Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) => {
+                        def = Region::Free(closure.def_id.to_def_id(), def.id().unwrap());
                     }
                     _ => {}
                 }
@@ -1283,7 +1290,7 @@ fn resolve_lifetime_ref(
 
         // We may fail to resolve higher-ranked lifetimes that are mentioned by APIT.
         // AST-based resolution does not care for impl-trait desugaring, which are the
-        // responibility of lowering.  This may create a mismatch between the resolution
+        // responibility of lowering. This may create a mismatch between the resolution
         // AST found (`region_def_id`) which points to HRTB, and what HIR allows.
         // ```
         // fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
@@ -1434,7 +1441,7 @@ fn visit_segment_args(
                         DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty),
                         DefKind::TyParam => Some(self.tcx.object_lifetime_default(param.def_id)),
                         // We may also get a `Trait` or `TraitAlias` because of how generics `Self` parameter
-                        // works.  Ignore it because it can't have a meaningful lifetime default.
+                        // works. Ignore it because it can't have a meaningful lifetime default.
                         DefKind::LifetimeParam | DefKind::Trait | DefKind::TraitAlias => None,
                         dk => bug!("unexpected def_kind {:?}", dk),
                     }
@@ -1658,10 +1665,12 @@ fn uninsert_lifetime_on_error(&mut self, lifetime_ref: &'tcx hir::Lifetime, bad_
 /// "Constrained" basically means that it appears in any type but
 /// not amongst the inputs to a projection. In other words, `<&'a
 /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
-fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<LocalDefId>> {
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let decl = tcx.hir().fn_decl_by_hir_id(hir_id)?;
-    let generics = tcx.hir().get_generics(def_id)?;
+fn is_late_bound_map(
+    tcx: TyCtxt<'_>,
+    owner_id: hir::OwnerId,
+) -> Option<&FxIndexSet<hir::ItemLocalId>> {
+    let decl = tcx.hir().fn_decl_by_hir_id(owner_id.into())?;
+    let generics = tcx.hir().get_generics(owner_id.def_id)?;
 
     let mut late_bound = FxIndexSet::default();
 
@@ -1695,24 +1704,22 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
             hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue,
         }
 
-        let param_def_id = tcx.hir().local_def_id(param.hir_id);
-
         // appears in the where clauses? early-bound.
-        if appears_in_where_clause.regions.contains(&param_def_id) {
+        if appears_in_where_clause.regions.contains(&param.def_id) {
             continue;
         }
 
         // does not appear in the inputs, but appears in the return type? early-bound.
-        if !constrained_by_input.regions.contains(&param_def_id)
-            && appears_in_output.regions.contains(&param_def_id)
+        if !constrained_by_input.regions.contains(&param.def_id)
+            && appears_in_output.regions.contains(&param.def_id)
         {
             continue;
         }
 
-        debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id);
+        debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.def_id);
 
-        let inserted = late_bound.insert(param_def_id);
-        assert!(inserted, "visited lifetime {:?} twice", param.hir_id);
+        let inserted = late_bound.insert(param.hir_id.local_id);
+        assert!(inserted, "visited lifetime {:?} twice", param.def_id);
     }
 
     debug!(?late_bound);
@@ -1828,7 +1835,7 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
                     }
                 }
 
-                hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
+                hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
                     // consider only the lifetimes on the final
                     // segment; I am not sure it's even currently
                     // valid to have them elsewhere, but even if it
index 234253556845bf264283ec24fedcfbd8c7549a86..d0d67ae9257c5ddcb959b28ee5f0e752c6fccc01 100644 (file)
@@ -85,29 +85,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
         Node::ImplItem(item) => item.generics,
 
         Node::Item(item) => match item.kind {
-            ItemKind::Impl(ref impl_) => {
+            ItemKind::Impl(impl_) => {
                 if impl_.defaultness.is_default() {
-                    is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
+                    is_default_impl_trait =
+                        tcx.impl_trait_ref(def_id).map(|t| ty::Binder::dummy(t.subst_identity()));
                 }
-                &impl_.generics
+                impl_.generics
             }
-            ItemKind::Fn(.., ref generics, _)
-            | ItemKind::TyAlias(_, ref generics)
-            | ItemKind::Enum(_, ref generics)
-            | ItemKind::Struct(_, ref generics)
-            | ItemKind::Union(_, ref generics) => *generics,
+            ItemKind::Fn(.., generics, _)
+            | ItemKind::TyAlias(_, generics)
+            | ItemKind::Enum(_, generics)
+            | ItemKind::Struct(_, generics)
+            | ItemKind::Union(_, generics) => generics,
 
-            ItemKind::Trait(_, _, ref generics, ..) | ItemKind::TraitAlias(ref generics, _) => {
+            ItemKind::Trait(_, _, generics, ..) | ItemKind::TraitAlias(generics, _) => {
                 is_trait = Some(ty::TraitRef::identity(tcx, def_id));
-                *generics
+                generics
             }
-            ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) => generics,
+            ItemKind::OpaqueTy(OpaqueTy { generics, .. }) => generics,
             _ => NO_GENERICS,
         },
 
         Node::ForeignItem(item) => match item.kind {
             ForeignItemKind::Static(..) => NO_GENERICS,
-            ForeignItemKind::Fn(_, _, ref generics) => *generics,
+            ForeignItemKind::Fn(_, _, generics) => generics,
             ForeignItemKind::Type => NO_GENERICS,
         },
 
@@ -246,12 +247,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
 
     // Subtle: before we store the predicates into the tcx, we
     // sort them so that predicates like `T: Foo<Item=U>` come
-    // before uses of `U`.  This avoids false ambiguity errors
+    // before uses of `U`. This avoids false ambiguity errors
     // in trait checking. See `setup_constraining_predicates`
     // for details.
     if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
         let self_ty = tcx.type_of(def_id);
-        let trait_ref = tcx.impl_trait_ref(def_id);
+        let trait_ref = tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::subst_identity);
         cgp::setup_constraining_predicates(
             tcx,
             &mut predicates,
@@ -279,7 +280,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
             }
 
             let hir::GenericParamKind::Lifetime { .. } = duplicate.kind else { continue };
-            let dup_def = tcx.hir().local_def_id(duplicate.hir_id).to_def_id();
+            let dup_def = duplicate.def_id.to_def_id();
 
             let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() };
 
@@ -349,7 +350,7 @@ fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst
     let node = tcx.hir().get(hir_id);
 
     let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
-    if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(ref impl_) = item.kind {
+    if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(impl_) = item.kind {
         if let Some(of_trait) = &impl_.of_trait {
             debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
             collector.visit_trait_ref(of_trait);
@@ -510,8 +511,8 @@ pub(super) fn super_predicates_that_define_assoc_type(
         };
 
         let (generics, bounds) = match item.kind {
-            hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
-            hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
+            hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits),
+            hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits),
             _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
         };
 
@@ -611,18 +612,18 @@ pub(super) fn type_param_predicates(
 
         Node::Item(item) => {
             match item.kind {
-                ItemKind::Fn(.., ref generics, _)
-                | ItemKind::Impl(hir::Impl { ref generics, .. })
-                | ItemKind::TyAlias(_, ref generics)
+                ItemKind::Fn(.., generics, _)
+                | ItemKind::Impl(&hir::Impl { generics, .. })
+                | ItemKind::TyAlias(_, generics)
                 | ItemKind::OpaqueTy(OpaqueTy {
-                    ref generics,
+                    generics,
                     origin: hir::OpaqueTyOrigin::TyAlias,
                     ..
                 })
-                | ItemKind::Enum(_, ref generics)
-                | ItemKind::Struct(_, ref generics)
-                | ItemKind::Union(_, ref generics) => generics,
-                ItemKind::Trait(_, _, ref generics, ..) => {
+                | ItemKind::Enum(_, generics)
+                | ItemKind::Struct(_, generics)
+                | ItemKind::Union(_, generics) => generics,
+                ItemKind::Trait(_, _, generics, ..) => {
                     // Implied `Self: Trait` and supertrait bounds.
                     if param_id == item_hir_id {
                         let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
@@ -636,7 +637,7 @@ pub(super) fn type_param_predicates(
         }
 
         Node::ForeignItem(item) => match item.kind {
-            ForeignItemKind::Fn(_, _, ref generics) => generics,
+            ForeignItemKind::Fn(_, _, generics) => generics,
             _ => return result,
         },
 
@@ -680,8 +681,8 @@ fn type_parameter_bounds_in_generics(
         ast_generics
             .predicates
             .iter()
-            .filter_map(|wp| match *wp {
-                hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
+            .filter_map(|wp| match wp {
+                hir::WherePredicate::BoundPredicate(bp) => Some(bp),
                 _ => None,
             })
             .flat_map(|bp| {
index 1f9a9f80302e3590957b9ef5a7d466ddfd860c1e..e7b0846e10352b1093b1d7efdd2174629513267e 100644 (file)
@@ -54,15 +54,14 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
             // ty which is a fully resolved projection.
             // For the code example above, this would mean converting Self::Assoc<3>
             // into a ty::Alias(ty::Projection, <Self as Foo>::Assoc<3>)
-            let item_hir_id = tcx
+            let item_def_id = tcx
                 .hir()
-                .parent_iter(hir_id)
-                .filter(|(_, node)| matches!(node, Node::Item(_)))
-                .map(|(id, _)| id)
-                .next()
-                .unwrap();
-            let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id();
-            let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>;
+                .parent_owner_iter(hir_id)
+                .find(|(_, node)| matches!(node, OwnerNode::Item(_)))
+                .unwrap()
+                .0
+                .to_def_id();
+            let item_ctxt = &ItemCtxt::new(tcx, item_def_id) as &dyn crate::astconv::AstConv<'_>;
             let ty = item_ctxt.ast_ty_to_ty(hir_ty);
 
             // Iterate through the generics of the projection to find the one that corresponds to
@@ -379,7 +378,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
             ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()),
         },
 
-        Node::Ctor(&ref def) | Node::Variant(Variant { data: ref def, .. }) => match *def {
+        Node::Ctor(def) | Node::Variant(Variant { data: def, .. }) => match def {
             VariantData::Unit(..) | VariantData::Struct(..) => {
                 tcx.type_of(tcx.hir().get_parent_item(hir_id))
             }
@@ -404,17 +403,17 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
         Node::AnonConst(_) => {
             let parent_node = tcx.hir().get_parent(hir_id);
             match parent_node {
-                Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
-                | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
+                Node::Ty(Ty { kind: TyKind::Array(_, constant), .. })
+                | Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
                     if constant.hir_id() == hir_id =>
                 {
                     tcx.types.usize
                 }
-                Node::Ty(&Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => {
+                Node::Ty(Ty { kind: TyKind::Typeof(e), .. }) if e.hir_id == hir_id => {
                     tcx.typeck(def_id).node_type(e.hir_id)
                 }
 
-                Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
+                Node::Expr(Expr { kind: ExprKind::ConstBlock(anon_const), .. })
                     if anon_const.hir_id == hir_id =>
                 {
                     let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
@@ -434,18 +433,19 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     tcx.typeck(def_id).node_type(hir_id)
                 }
 
-                Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
+                Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => {
                     tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
                 }
 
                 Node::TypeBinding(
-                    binding @ &TypeBinding {
+                    TypeBinding {
                         hir_id: binding_id,
-                        kind: TypeBindingKind::Equality { term: Term::Const(ref e) },
+                        kind: TypeBindingKind::Equality { term: Term::Const(e) },
+                        ident,
                         ..
                     },
                 ) if let Node::TraitRef(trait_ref) =
-                    tcx.hir().get_parent(binding_id)
+                    tcx.hir().get_parent(*binding_id)
                     && e.hir_id == hir_id =>
                 {
                     let Some(trait_def_id) = trait_ref.trait_def_id() else {
@@ -454,7 +454,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     let assoc_items = tcx.associated_items(trait_def_id);
                     let assoc_item = assoc_items.find_by_name_and_kind(
                         tcx,
-                        binding.ident,
+                        *ident,
                         ty::AssocKind::Const,
                         def_id.to_def_id(),
                     );
@@ -470,9 +470,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                 }
 
                 Node::TypeBinding(
-                    binding @ &TypeBinding { hir_id: binding_id, gen_args, ref kind, .. },
+                    TypeBinding { hir_id: binding_id, gen_args, kind, ident, .. },
                 ) if let Node::TraitRef(trait_ref) =
-                    tcx.hir().get_parent(binding_id)
+                    tcx.hir().get_parent(*binding_id)
                     && let Some((idx, _)) =
                         gen_args.args.iter().enumerate().find(|(_, arg)| {
                             if let GenericArg::Const(ct) = arg {
@@ -488,7 +488,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     let assoc_items = tcx.associated_items(trait_def_id);
                     let assoc_item = assoc_items.find_by_name_and_kind(
                         tcx,
-                        binding.ident,
+                        *ident,
                         match kind {
                             // I think `<A: T>` type bindings requires that `A` is a type
                             TypeBindingKind::Constraint { .. }
@@ -866,7 +866,9 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             }
 
             match ty.kind() {
-                ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)),
+                ty::FnDef(def_id, substs) => {
+                    self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id).subst(self.tcx, substs))
+                }
                 // FIXME: non-capturing closures should also suggest a function pointer
                 ty::Closure(..) | ty::Generator(..) => {
                     self.success = false;
index 95c971c0d7845eee2d63668b8527c419b67eb4e6..56cc1d8fadc00e7ac6e9611c18dd0f5bcdf3039a 100644 (file)
@@ -61,7 +61,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match *t.kind() {
             ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => {
                 // projections are not injective
-                return ControlFlow::CONTINUE;
+                return ControlFlow::Continue(());
             }
             ty::Param(data) => {
                 self.parameters.push(Parameter::from(data));
@@ -76,7 +76,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         if let ty::ReEarlyBound(data) = *r {
             self.parameters.push(Parameter::from(data));
         }
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 
     fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
index 2dbfc1bc9a229c4a4a069ddf76ab79cbb26db179..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,
     };
@@ -128,7 +129,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
             },
             hir::Node::Item(item) => match item.kind {
                 hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => vec![ty],
-                hir::ItemKind::Impl(ref impl_) => match &impl_.of_trait {
+                hir::ItemKind::Impl(impl_) => match &impl_.of_trait {
                     Some(t) => t
                         .path
                         .segments
index 136f6199911a0eeb9ba7ac07032bf630df2eef6a..4fe893442b9bd2987c0ed22233a1eb88a2fe5c9c 100644 (file)
@@ -85,7 +85,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
     }
     let impl_generics = tcx.generics_of(impl_def_id);
     let impl_predicates = tcx.predicates_of(impl_def_id);
-    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
+    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::subst_identity);
 
     let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
     cgp::identify_constrained_generic_params(
index 8b9034d9620e2c3debfefc0081b6f3fdcf4217c9..a5dcfab9be8e84d102923a58822f232df27731e8 100644 (file)
@@ -90,7 +90,7 @@ pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
 
 fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Option<Node> {
     let trait_ref = tcx.impl_trait_ref(impl1_def_id)?;
-    let trait_def = tcx.trait_def(trait_ref.def_id);
+    let trait_def = tcx.trait_def(trait_ref.skip_binder().def_id);
 
     let impl2_node = trait_def.ancestors(tcx, impl1_def_id.to_def_id()).ok()?.nth(1)?;
 
@@ -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);
@@ -207,7 +206,7 @@ fn unconstrained_parent_impl_substs<'tcx>(
     let impl_generic_predicates = tcx.predicates_of(impl_def_id);
     let mut unconstrained_parameters = FxHashSet::default();
     let mut constrained_params = FxHashSet::default();
-    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
+    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::subst_identity);
 
     // Unfortunately the functions in `constrained_generic_parameters` don't do
     // what we want here. We want only a list of constrained parameters while
@@ -370,17 +369,11 @@ 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().substs {
+    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 ddc5b7668812668e9e6f923956ba85bd0a2cb484..c2fa46e563e60ac60d7149bb4fc8dd45d03c7a72 100644 (file)
@@ -22,7 +22,7 @@
 4. Finally, the check phase then checks function bodies and so forth.
    Within the check phase, we check each function body one at a time
    (bodies of function expressions are checked as part of the
-   containing function).  Inference is used to supply types wherever
+   containing function). Inference is used to supply types wherever
    they are unknown. The actual checking of a function itself has
    several phases (check, regionck, writeback), as discussed in the
    documentation for the [`check`] module.
@@ -46,7 +46,7 @@
   local variables, type parameters, etc as necessary.
 
 - infer: finds the types to use for each type variable such that
-  all subtyping and assignment constraints are met.  In essence, the check
+  all subtyping and assignment constraints are met. In essence, the check
   module specifies the constraints, and the infer module solves them.
 
 ## Note
 
 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 _;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use std::iter;
+use std::ops::Not;
 
 use astconv::AstConv;
 use bounds::Bounds;
@@ -181,19 +182,18 @@ fn require_same_types<'tcx>(
 }
 
 fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
-    let main_fnsig = tcx.fn_sig(main_def_id);
+    let main_fnsig = tcx.fn_sig(main_def_id).subst_identity();
     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
         }
     }
 
@@ -203,12 +203,8 @@ fn main_fn_generics_params_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span>
         }
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
         match tcx.hir().find(hir_id) {
-            Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
-                if !generics.params.is_empty() {
-                    Some(generics.span)
-                } else {
-                    None
-                }
+            Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => {
+                generics.params.is_empty().not().then(|| generics.span)
             }
             _ => {
                 span_bug!(tcx.def_span(def_id), "main has a non-function type");
@@ -222,7 +218,7 @@ fn main_fn_where_clauses_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         }
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
         match tcx.hir().find(hir_id) {
-            Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
+            Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => {
                 Some(generics.where_clause_span)
             }
             _ => {
@@ -244,7 +240,7 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         }
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
         match tcx.hir().find(hir_id) {
-            Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(ref fn_sig, _, _), .. })) => {
+            Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. })) => {
                 Some(fn_sig.decl.output.span())
             }
             _ => {
@@ -254,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() {
@@ -329,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);
@@ -359,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,
@@ -374,7 +370,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
     match start_t.kind() {
         ty::FnDef(..) => {
             if let Some(Node::Item(it)) = tcx.hir().find(start_id) {
-                if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind {
+                if let hir::ItemKind::Fn(sig, generics, _) = &it.kind {
                     let mut error = false;
                     if !generics.params.is_empty() {
                         struct_span_err!(
@@ -447,9 +443,13 @@ 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)),
+                tcx.mk_fn_ptr(tcx.fn_sig(start_def_id).subst_identity()),
             );
         }
         _ => {
@@ -542,7 +542,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
 pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
     // In case there are any projections, etc., find the "environment"
     // def-ID that will be used to determine the traits/predicates in
-    // scope.  This is derived from the enclosing item-like thing.
+    // scope. This is derived from the enclosing item-like thing.
     let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
     item_cx.astconv().ast_ty_to_ty(hir_ty)
@@ -555,7 +555,7 @@ pub fn hir_trait_to_predicates<'tcx>(
 ) -> Bounds<'tcx> {
     // In case there are any projections, etc., find the "environment"
     // def-ID that will be used to determine the traits/predicates in
-    // scope.  This is derived from the enclosing item-like thing.
+    // scope. This is derived from the enclosing item-like thing.
     let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
     let mut bounds = Bounds::default();
index a46f2a94cd281a17006d5cb2a6be6332eaabb661..925042436dec150821c957051f7f13283069b84e 100644 (file)
@@ -139,7 +139,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                 if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did()) {
                     for (unsubstituted_predicate, &span) in &unsubstituted_predicates.0 {
                         // `unsubstituted_predicate` is `U: 'b` in the
-                        // example above.  So apply the substitution to
+                        // example above. So apply the substitution to
                         // get `T: 'a` (or `predicate`):
                         let predicate = unsubstituted_predicates
                             .rebind(*unsubstituted_predicate)
index b51b740d08e2e7a2e87f7bb578205bbcc430237c..9459c5f54abbf7c0105f3666c1c347b39efb5964 100644 (file)
@@ -48,7 +48,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
                         // ```
                         //
                         // Here `outlived_region = 'a` and `kind = &'b
-                        // u32`.  Decomposing `&'b u32` into
+                        // u32`. Decomposing `&'b u32` into
                         // components would yield `'b`, and we add the
                         // where clause that `'b: 'a`.
                         insert_outlives_predicate(
@@ -71,7 +71,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
                         // ```
                         //
                         // Here `outlived_region = 'a` and `kind =
-                        // Vec<U>`.  Decomposing `Vec<U>` into
+                        // Vec<U>`. Decomposing `Vec<U>` into
                         // components would yield `U`, and we add the
                         // where clause that `U: 'a`.
                         let ty: Ty<'tcx> = param_ty.to_ty(tcx);
@@ -80,8 +80,8 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
                             .or_insert(span);
                     }
 
-                    Component::Projection(proj_ty) => {
-                        // This would arise from something like:
+                    Component::Alias(alias_ty) => {
+                        // This would either arise from something like:
                         //
                         // ```
                         // struct Foo<'a, T: Iterator> {
@@ -89,15 +89,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
                         // }
                         // ```
                         //
-                        // Here we want to add an explicit `where <T as Iterator>::Item: 'a`.
-                        let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.def_id, proj_ty.substs);
-                        required_predicates
-                            .entry(ty::OutlivesPredicate(ty.into(), outlived_region))
-                            .or_insert(span);
-                    }
-
-                    Component::Opaque(def_id, substs) => {
-                        // This would arise from something like:
+                        // or:
                         //
                         // ```rust
                         // type Opaque<T> = impl Sized;
@@ -105,17 +97,17 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
                         // struct Ss<'a, T>(&'a Opaque<T>);
                         // ```
                         //
-                        // Here we want to have an implied bound `Opaque<T>: 'a`
-
-                        let ty = tcx.mk_opaque(def_id, substs);
+                        // Here we want to add an explicit `where <T as Iterator>::Item: 'a`
+                        // or `Opaque<T>: 'a` depending on the alias kind.
+                        let ty = alias_ty.to_ty(tcx);
                         required_predicates
                             .entry(ty::OutlivesPredicate(ty.into(), outlived_region))
                             .or_insert(span);
                     }
 
-                    Component::EscapingProjection(_) => {
+                    Component::EscapingAlias(_) => {
                         // As above, but the projection involves
-                        // late-bound regions.  Therefore, the WF
+                        // late-bound regions. Therefore, the WF
                         // requirement is not checked in type definition
                         // but at fn call site, so ignore it.
                         //
@@ -175,7 +167,7 @@ fn is_free_region(region: Region<'_>) -> bool {
         //     }
         //
         // The type above might generate a `T: 'b` bound, but we can
-        // ignore it.  We can't put it on the struct header anyway.
+        // ignore it. We can't put it on the struct header anyway.
         ty::ReLateBound(..) => false,
 
         // These regions don't appear in types from type declarations:
index 574b1e8b485afad6ffc8d1ada76b48f564d73786..9133e6540d4450e07e96f9742c8115d8553e9722 100644 (file)
@@ -727,8 +727,8 @@ fn suggest_moving_args_from_assoc_fn_to_trait(&self, err: &mut Diagnostic) {
         if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id)
         && let Some(parent_node) = self.tcx.hir().find(parent_node)
         && let hir::Node::Expr(expr) = parent_node {
-            match expr.kind {
-                hir::ExprKind::Path(ref qpath) => {
+            match &expr.kind {
+                hir::ExprKind::Path(qpath) => {
                     self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
                         err,
                         qpath,
index 5e4d82b6fd5697ce31b095b0431a804f67d383f5..165782f209a0ce925418ef909f926d61db62a5b8 100644 (file)
@@ -119,7 +119,11 @@ fn build_constraints_for_item(&mut self, def_id: LocalDefId) {
             }
 
             ty::FnDef(..) => {
-                self.add_constraints_from_sig(current_item, tcx.fn_sig(def_id), self.covariant);
+                self.add_constraints_from_sig(
+                    current_item,
+                    tcx.fn_sig(def_id).subst_identity(),
+                    self.covariant,
+                );
             }
 
             ty::Error(_) => {}
@@ -221,8 +225,7 @@ fn add_constraints_from_ty(
             }
 
             ty::Ref(region, ty, mutbl) => {
-                let contra = self.contravariant(variance);
-                self.add_constraints_from_region(current, region, contra);
+                self.add_constraints_from_region(current, region, variance);
                 self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
             }
 
@@ -254,9 +257,8 @@ fn add_constraints_from_ty(
             }
 
             ty::Dynamic(data, r, _) => {
-                // The type `Foo<T+'a>` is contravariant w/r/t `'a`:
-                let contra = self.contravariant(variance);
-                self.add_constraints_from_region(current, r, contra);
+                // The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
+                self.add_constraints_from_region(current, r, variance);
 
                 if let Some(poly_trait_ref) = data.principal() {
                     self.add_constraints_from_invariant_substs(
@@ -291,12 +293,12 @@ fn add_constraints_from_ty(
                 // types, where we use Error as the Self type
             }
 
-            ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Bound(..) | ty::Infer(..) => {
-                bug!(
-                    "unexpected type encountered in \
-                      variance inference: {}",
-                    ty
-                );
+            ty::Placeholder(..)
+            | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..)
+            | ty::Bound(..)
+            | ty::Infer(..) => {
+                bug!("unexpected type encountered in variance inference: {}", ty);
             }
         }
     }
index 24008f88814339d1f343fe38c0cf368165afe994..079070be27983a8c72f5d04120ffff76e660ed81 100644 (file)
@@ -92,7 +92,7 @@ fn visit_opaque(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> ControlFlo
                         a.visit_with(self)?;
                     }
                 }
-                ControlFlow::CONTINUE
+                ControlFlow::Continue(())
             } else {
                 substs.visit_with(self)
             }
index 97aca621aa21745e78cfc319bd6acf089c5e9fd4..a17edb598ad5e5eb79d86072571bbc55fda8c2c3 100644 (file)
@@ -5,8 +5,7 @@
 //! optimal solution to the constraints. The final variance for each
 //! inferred is then written into the `variance_map` in the tcx.
 
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::DefIdMap;
 use rustc_middle::ty;
 
 use super::constraints::*;
@@ -28,8 +27,8 @@ pub fn solve_constraints<'tcx>(
     let ConstraintContext { terms_cx, constraints, .. } = constraints_cx;
 
     let mut solutions = vec![ty::Bivariant; terms_cx.inferred_terms.len()];
-    for &(id, ref variances) in &terms_cx.lang_items {
-        let InferredIndex(start) = terms_cx.inferred_starts[&id];
+    for (id, variances) in &terms_cx.lang_items {
+        let InferredIndex(start) = terms_cx.inferred_starts[id];
         for (i, &variance) in variances.iter().enumerate() {
             solutions[start + i] = variance;
         }
@@ -44,7 +43,7 @@ pub fn solve_constraints<'tcx>(
 
 impl<'a, 'tcx> SolveContext<'a, 'tcx> {
     fn solve(&mut self) {
-        // Propagate constraints until a fixed point is reached.  Note
+        // Propagate constraints until a fixed point is reached. Note
         // that the maximum number of iterations is 2C where C is the
         // number of constraints (each variable can change values at most
         // twice). Since number of constraints is linear in size of the
@@ -89,14 +88,12 @@ fn enforce_const_invariance(&self, generics: &ty::Generics, variances: &mut [ty:
         }
     }
 
-    fn create_map(&self) -> FxHashMap<DefId, &'tcx [ty::Variance]> {
+    fn create_map(&self) -> DefIdMap<&'tcx [ty::Variance]> {
         let tcx = self.terms_cx.tcx;
 
         let solutions = &self.solutions;
-        self.terms_cx
-            .inferred_starts
-            .iter()
-            .map(|(&def_id, &InferredIndex(start))| {
+        DefIdMap::from(self.terms_cx.inferred_starts.items().map(
+            |(&def_id, &InferredIndex(start))| {
                 let generics = tcx.generics_of(def_id);
                 let count = generics.count();
 
@@ -115,8 +112,8 @@ fn create_map(&self) -> FxHashMap<DefId, &'tcx [ty::Variance]> {
                 }
 
                 (def_id.to_def_id(), &*variances)
-            })
-            .collect()
+            },
+        ))
     }
 
     fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance {
index 83ed3e44b3d733ca28477c985a4674c1eb201041..5feeb92d3378251e9e551acf2a435c9c24134c62 100644 (file)
@@ -1,4 +1,3 @@
-use rustc_errors::struct_span_err;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
 
@@ -8,8 +7,8 @@ pub fn test_variance(tcx: TyCtxt<'_>) {
     for id in tcx.hir().items() {
         if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) {
             let variances_of = tcx.variances_of(id.owner_id);
-            struct_span_err!(tcx.sess, tcx.def_span(id.owner_id), E0208, "{:?}", variances_of)
-                .emit();
+
+            tcx.sess.struct_span_err(tcx.def_span(id.owner_id), format!("{variances_of:?}")).emit();
         }
     }
 }
index b6f19d3cc684ae1d84fc97b0c1f3fd390af54975..88fb26535868603907dfdd4ec89c8678f301c024 100644 (file)
@@ -188,8 +188,9 @@ fn suggest_removing_semicolon_for_coerce(
         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 +199,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 8d417290407ed033049bbe2d48afb48b99d94c2a..c220956a2012e15620f124c86c5942b479587759 100644 (file)
@@ -367,7 +367,7 @@ fn confirm_builtin_call(
     ) -> Ty<'tcx> {
         let (fn_sig, def_id) = match *callee_ty.kind() {
             ty::FnDef(def_id, subst) => {
-                let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, subst);
+                let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, subst);
 
                 // Unit testing: function items annotated with
                 // `#[rustc_evaluate_where_clauses]` trigger special output
@@ -375,14 +375,12 @@ fn confirm_builtin_call(
                 if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
                     let predicates = self.tcx.predicates_of(def_id);
                     let predicates = predicates.instantiate(self.tcx, subst);
-                    for (predicate, predicate_span) in
-                        predicates.predicates.iter().zip(&predicates.spans)
-                    {
+                    for (predicate, predicate_span) in predicates {
                         let obligation = Obligation::new(
                             self.tcx,
                             ObligationCause::dummy_with_span(callee_expr.span),
                             self.param_env,
-                            *predicate,
+                            predicate,
                         );
                         let result = self.evaluate_obligation(&obligation);
                         self.tcx
@@ -391,7 +389,7 @@ fn confirm_builtin_call(
                                 callee_expr.span,
                                 &format!("evaluate({:?}) = {:?}", predicate, result),
                             )
-                            .span_label(*predicate_span, "predicate")
+                            .span_label(predicate_span, "predicate")
                             .emit();
                     }
                 }
@@ -659,8 +657,7 @@ fn report_invalid_callee(
         };
 
         if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
-            if let Some((maybe_def, output_ty, _)) =
-                self.extract_callable_info(callee_expr, callee_ty)
+            if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty)
                 && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
             {
                 let descr = match maybe_def {
index 042a50f2fd42eb89906167fde85ed9b0e4eb1622..8e21c084841d0d1707edea19be3f534c4fb7fd36 100644 (file)
 use super::FnCtxt;
 
 use crate::type_error_struct;
-use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
+use hir::ExprKind;
+use rustc_errors::{
+    struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+};
 use rustc_hir as hir;
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::mir::Mutability;
@@ -127,6 +130,7 @@ fn pointer_kind(
             | ty::Float(_)
             | ty::Array(..)
             | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..)
             | ty::RawPtr(_)
             | ty::Ref(..)
             | ty::FnDef(..)
@@ -149,7 +153,7 @@ fn pointer_kind(
 
 #[derive(Copy, Clone)]
 pub enum CastError {
-    ErrorGuaranteed,
+    ErrorGuaranteed(ErrorGuaranteed),
 
     CastToBool,
     CastToChar,
@@ -174,8 +178,8 @@ pub enum CastError {
 }
 
 impl From<ErrorGuaranteed> for CastError {
-    fn from(_: ErrorGuaranteed) -> Self {
-        CastError::ErrorGuaranteed
+    fn from(err: ErrorGuaranteed) -> Self {
+        CastError::ErrorGuaranteed(err)
     }
 }
 
@@ -223,11 +227,10 @@ pub fn new(
 
     fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
         match e {
-            CastError::ErrorGuaranteed => {
+            CastError::ErrorGuaranteed(_) => {
                 // an error has already been reported
             }
             CastError::NeedDeref => {
-                let error_span = self.span;
                 let mut err = make_invalid_casting_error(
                     fcx.tcx.sess,
                     self.span,
@@ -235,21 +238,25 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                     self.cast_ty,
                     fcx,
                 );
-                let cast_ty = fcx.ty_to_string(self.cast_ty);
-                err.span_label(
-                    error_span,
-                    format!("cannot cast `{}` as `{}`", fcx.ty_to_string(self.expr_ty), cast_ty),
-                );
-                if let Ok(snippet) = fcx.sess().source_map().span_to_snippet(self.expr_span) {
-                    err.span_suggestion(
-                        self.expr_span,
-                        "dereference the expression",
-                        format!("*{}", snippet),
-                        Applicability::MaybeIncorrect,
+
+                if matches!(self.expr.kind, ExprKind::AddrOf(..)) {
+                    // get just the borrow part of the expression
+                    let span = self.expr_span.with_hi(self.expr.peel_borrows().span.lo());
+                    err.span_suggestion_verbose(
+                        span,
+                        "remove the unneeded borrow",
+                        "",
+                        Applicability::MachineApplicable,
                     );
                 } else {
-                    err.span_help(self.expr_span, "dereference the expression with `*`");
+                    err.span_suggestion_verbose(
+                        self.expr_span.shrink_to_lo(),
+                        "dereference the expression",
+                        "*",
+                        Applicability::MachineApplicable,
+                    );
                 }
+
                 err.emit();
             }
             CastError::NeedViaThinPtr | CastError::NeedViaPtr => {
@@ -270,6 +277,9 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                         }
                     ));
                 }
+
+                self.try_suggest_collection_to_bool(fcx, &mut err);
+
                 err.emit();
             }
             CastError::NeedViaInt => {
@@ -517,6 +527,9 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                 } else {
                     err.span_label(self.span, "invalid cast");
                 }
+
+                self.try_suggest_collection_to_bool(fcx, &mut err);
+
                 err.emit();
             }
             CastError::SizedUnsizedCast => {
@@ -1080,4 +1093,40 @@ fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
             },
         );
     }
+
+    /// Attempt to suggest using `.is_empty` when trying to cast from a
+    /// collection type to a boolean.
+    fn try_suggest_collection_to_bool(&self, fcx: &FnCtxt<'a, 'tcx>, err: &mut Diagnostic) {
+        if self.cast_ty.is_bool() {
+            let derefed = fcx
+                .autoderef(self.expr_span, self.expr_ty)
+                .silence_errors()
+                .find(|t| matches!(t.0.kind(), ty::Str | ty::Slice(..)));
+
+            if let Some((deref_ty, _)) = derefed {
+                // Give a note about what the expr derefs to.
+                if deref_ty != self.expr_ty.peel_refs() {
+                    err.span_note(
+                        self.expr_span,
+                        format!(
+                            "this expression `Deref`s to `{}` which implements `is_empty`",
+                            fcx.ty_to_string(deref_ty)
+                        ),
+                    );
+                }
+
+                // Create a multipart suggestion: add `!` and `.is_empty()` in
+                // place of the cast.
+                let suggestion = vec![
+                    (self.expr_span.shrink_to_lo(), "!".to_string()),
+                    (self.span.with_lo(self.expr_span.hi()), ".is_empty()".to_string()),
+                ];
+
+                err.multipart_suggestion_verbose(format!(
+                    "consider using the `is_empty` method on `{}` to determine if it contains anything",
+                    fcx.ty_to_string(self.expr_ty),
+                ),  suggestion, Applicability::MaybeIncorrect);
+            }
+        }
+    }
 }
index 57feefbcab6c8cc25b246e313fbf2fbd39f2dced..1c70c1b71e7639315f741329413e96be905b73b3 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,
         ));
@@ -130,7 +130,12 @@ pub(super) fn check_fn<'a, 'tcx>(
     let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
         let interior = fcx
             .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
-        fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
+        fcx.deferred_generator_interiors.borrow_mut().push((
+            fn_def_id,
+            body.id(),
+            interior,
+            gen_kind,
+        ));
 
         let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
         Some(GeneratorTypes {
@@ -167,12 +172,12 @@ pub(super) fn check_fn<'a, 'tcx>(
 
     // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
     if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
-        && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
+        && panic_impl_did == fn_def_id.to_def_id()
     {
         check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
     }
 
-    if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == hir.local_def_id(fn_id).to_def_id() {
+    if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == fn_def_id.to_def_id() {
         check_lang_start_fn(tcx, fn_sig, decl, fn_def_id);
     }
 
index 399702fd41abcdabbeb055e5629452d6ddc3f0e8..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,
@@ -236,7 +236,7 @@ impl<'tcx> TypeVisitor<'tcx> for MentionsTy<'tcx> {
 
                     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                         if t == self.expected_ty {
-                            ControlFlow::BREAK
+                            ControlFlow::Break(())
                         } else {
                             t.super_visit_with(self)
                         }
@@ -524,7 +524,7 @@ fn merge_supplied_sig_with_expectation(
 
         // FIXME(#45727): As discussed in [this comment][c1], naively
         // forcing equality here actually results in suboptimal error
-        // messages in some cases.  For now, if there would have been
+        // messages in some cases. For now, if there would have been
         // an obvious error, we fallback to declaring the type of the
         // closure to be the one the user gave, which allows other
         // error message code to trigger.
@@ -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 7e1c0faa453a26f08b87472f77d09cc51b237a2e..ade9c037c519405d04470edbf8c5741f8e9cba07 100644 (file)
@@ -313,7 +313,7 @@ fn coerce_borrowed_pointer(
 
         // If we have a parameter of type `&M T_a` and the value
         // provided is `expr`, we will be adding an implicit borrow,
-        // meaning that we convert `f(expr)` to `f(&M *expr)`.  Therefore,
+        // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore,
         // to type check, we will construct the type that `&M*expr` would
         // yield.
 
@@ -340,7 +340,7 @@ fn coerce_borrowed_pointer(
                 continue;
             }
 
-            // At this point, we have deref'd `a` to `referent_ty`.  So
+            // At this point, we have deref'd `a` to `referent_ty`. So
             // imagine we are coercing from `&'a mut Vec<T>` to `&'b mut [T]`.
             // In the autoderef loop for `&'a mut Vec<T>`, we would get
             // three callbacks:
@@ -371,7 +371,7 @@ fn coerce_borrowed_pointer(
             // - if in sub mode, that means we want to use `'b` (the
             //   region from the target reference) for both
             //   pointers [2]. This is because sub mode (somewhat
-            //   arbitrarily) returns the subtype region.  In the case
+            //   arbitrarily) returns the subtype region. In the case
             //   where we are coercing to a target type, we know we
             //   want to use that target type region (`'b`) because --
             //   for the program to type-check -- it must be the
@@ -383,7 +383,7 @@ fn coerce_borrowed_pointer(
             //     annotate the region of a borrow), and regionck has
             //     code that adds edges from the region of a borrow
             //     (`'b`, here) into the regions in the borrowed
-            //     expression (`*x`, here).  (Search for "link".)
+            //     expression (`*x`, here). (Search for "link".)
             // - if in lub mode, things can get fairly complicated. The
             //   easiest thing is just to make a fresh
             //   region variable [4], which effectively means we defer
@@ -457,7 +457,7 @@ fn coerce_borrowed_pointer(
         if ty == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 {
             // As a special case, if we would produce `&'a *x`, that's
             // a total no-op. We end up with the type `&'a T` just as
-            // we started with.  In that case, just skip it
+            // we started with. In that case, just skip it
             // altogether. This is just an optimization.
             //
             // Note that for `&mut`, we DO want to reborrow --
@@ -1476,7 +1476,7 @@ pub(crate) fn coerce_inner<'a>(
             //     if let Some(x) = ... { }
             //
             // we wind up with a second match arm that is like `_ =>
-            // ()`.  That is the case we are considering here. We take
+            // ()`. That is the case we are considering here. We take
             // a different path to get the right "expected, found"
             // message and so forth (and because we know that
             // `expression_ty` will be unit).
@@ -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,
@@ -1821,7 +1823,7 @@ fn add_impl_trait_explanation<'a>(
                         .trait_ref()
                         .and_then(|t| t.trait_def_id())
                         .map_or(false, |def_id| {
-                            fcx.tcx.object_safety_violations(def_id).is_empty()
+                            fcx.tcx.check_is_object_safe(def_id)
                         })
                 })
             }
index 6c128d0aa1a658ffa149a45c995d75d0c3b3c555..19b8fb96cde37133145ed156b3477c887c8225ee 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,10 +82,10 @@ 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);
+        self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty);
     }
 
     /// Requires that the two types unify, and prints an error message if
@@ -221,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();
 
@@ -269,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 }))
                 }
@@ -280,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
@@ -297,7 +299,7 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
             {
                 // We special case methods, because they can influence inference through the
                 // call's arguments and we can provide a more explicit span.
-                let sig = self.tcx.fn_sig(def_id);
+                let sig = self.tcx.fn_sig(def_id).subst_identity();
                 let def_self_ty = sig.input(0).skip_binder();
                 let rcvr_ty = self.node_ty(rcvr.hir_id);
                 // Get the evaluated type *after* calling the method call, so that the influence
@@ -332,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));
                         }
                     }
@@ -381,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;
@@ -405,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;
@@ -596,6 +603,12 @@ fn annotate_alternative_method_deref(
                 let substs = ty::InternalSubsts::for_item(self.tcx, m.def_id, |param, _| {
                     self.var_for_def(deref.span, param)
                 });
+                let mutability =
+                    match self.tcx.fn_sig(m.def_id).skip_binder().input(0).skip_binder().kind() {
+                        ty::Ref(_, _, hir::Mutability::Mut) => "&mut ",
+                        ty::Ref(_, _, _) => "&",
+                        _ => "",
+                    };
                 vec![
                     (
                         deref.span.until(base.span),
@@ -604,11 +617,7 @@ fn annotate_alternative_method_deref(
                             with_no_trimmed_paths!(
                                 self.tcx.def_path_str_with_substs(m.def_id, substs,)
                             ),
-                            match self.tcx.fn_sig(m.def_id).input(0).skip_binder().kind() {
-                                ty::Ref(_, _, hir::Mutability::Mut) => "&mut ",
-                                ty::Ref(_, _, _) => "&",
-                                _ => "",
-                            },
+                            mutability,
                         ),
                     ),
                     match &args[..] {
@@ -696,6 +705,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(
@@ -979,7 +1038,8 @@ fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
         match method.kind {
             ty::AssocKind::Fn => {
                 method.fn_has_self_parameter
-                    && self.tcx.fn_sig(method.def_id).inputs().skip_binder().len() == 1
+                    && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len()
+                        == 1
             }
             _ => false,
         }
@@ -1232,6 +1292,22 @@ pub fn check_ref(
                             sugg_sp = receiver.span;
                         }
                     }
+
+                    if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner) = expr.kind
+                        && let Some(1) = self.deref_steps(expected, checked_ty) {
+                        // We have `*&T`, check if what was expected was `&T`.
+                        // If so, we may want to suggest removing a `*`.
+                        sugg_sp = sugg_sp.with_hi(inner.span.lo());
+                        return Some((
+                            sugg_sp,
+                            "consider removing deref here".to_string(),
+                            "".to_string(),
+                            Applicability::MachineApplicable,
+                            true,
+                            false,
+                        ));
+                    }
+
                     if let Ok(src) = sm.span_to_snippet(sugg_sp) {
                         let needs_parens = match expr.kind {
                             // parenthesize if needed (Issue #46756)
@@ -1941,4 +2017,77 @@ fn check_for_binding_assigned_block_without_tail_expression(
             err.span_label(block.span, "this block is missing a tail expression");
         }
     }
+
+    fn check_wrong_return_type_due_to_generic_arg(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+        checked_ty: Ty<'tcx>,
+    ) {
+        let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; };
+        enum CallableKind {
+            Function,
+            Method,
+            Constructor,
+        }
+        let mut maybe_emit_help = |def_id: hir::def_id::DefId,
+                                   callable: rustc_span::symbol::Ident,
+                                   args: &[hir::Expr<'_>],
+                                   kind: CallableKind| {
+            let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap();
+            let fn_ty = self.tcx.bound_type_of(def_id).0;
+            if !fn_ty.is_fn() {
+                return;
+            }
+            let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder();
+            let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; };
+            if matches!(arg.kind(), ty::Param(_))
+                && fn_sig.output().contains(arg)
+                && self.node_ty(args[arg_idx].hir_id) == checked_ty
+            {
+                let mut multi_span: MultiSpan = parent_expr.span.into();
+                multi_span.push_span_label(
+                    args[arg_idx].span,
+                    format!(
+                        "this argument influences the {} of `{}`",
+                        if matches!(kind, CallableKind::Constructor) {
+                            "type"
+                        } else {
+                            "return type"
+                        },
+                        callable
+                    ),
+                );
+                err.span_help(
+                    multi_span,
+                    format!(
+                        "the {} `{}` due to the type of the argument passed",
+                        match kind {
+                            CallableKind::Function => "return type of this call is",
+                            CallableKind::Method => "return type of this call is",
+                            CallableKind::Constructor => "type constructed contains",
+                        },
+                        checked_ty
+                    ),
+                );
+            }
+        };
+        match parent_expr.kind {
+            hir::ExprKind::Call(fun, args) => {
+                let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; };
+                let hir::def::Res::Def(kind, def_id) = path.res else { return; };
+                let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) {
+                    CallableKind::Constructor
+                } else {
+                    CallableKind::Function
+                };
+                maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind);
+            }
+            hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
+                let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; };
+                maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
+            }
+            _ => return,
+        }
+    }
 }
index ba1a5a0cb03e114312a39f3ca23a70404707d781..74913bac72411a7b73d771648c088367fc541db5 100644 (file)
@@ -459,9 +459,9 @@ fn check_expr_addr_of(
             }
             hir::BorrowKind::Ref => {
                 // Note: at this point, we cannot say what the best lifetime
-                // is to use for resulting pointer.  We want to use the
+                // is to use for resulting pointer. We want to use the
                 // shortest lifetime possible so as to avoid spurious borrowck
-                // errors.  Moreover, the longest lifetime will depend on the
+                // errors. Moreover, the longest lifetime will depend on the
                 // precise details of the value whose address is being taken
                 // (and how long it is valid), which we don't know yet until
                 // type inference is complete.
@@ -542,7 +542,9 @@ pub(crate) fn check_expr_path(
 
         if let ty::FnDef(did, ..) = *ty.kind() {
             let fn_sig = ty.fn_sig(tcx);
-            if tcx.fn_sig(did).abi() == RustIntrinsic && tcx.item_name(did) == sym::transmute {
+            if tcx.fn_sig(did).skip_binder().abi() == RustIntrinsic
+                && tcx.item_name(did) == sym::transmute
+            {
                 let from = fn_sig.inputs().skip_binder()[0];
                 let to = fn_sig.output().skip_binder();
                 // We defer the transmute to the end of typeck, once all inference vars have
@@ -687,7 +689,7 @@ fn check_expr_break(
                 }
             } else {
                 // If `ctxt.coerce` is `None`, we can just ignore
-                // the type of the expression.  This is because
+                // the type of the expression. This is because
                 // either this was a break *without* a value, in
                 // which case it is always a legal type (`()`), or
                 // else an error would have been flagged by the
@@ -852,7 +854,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 +864,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 +1377,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 +2155,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 +2208,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 +2548,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 7774ffc9b9793ea8ac6a93a0e41b9ca196514a71..c8cda0dc90c6daf39095057859453ec164196609 100644 (file)
@@ -417,7 +417,7 @@ fn maybe_read_scrutinee<'t>(
                                 // Named constants have to be equated with the value
                                 // being matched, so that's a read of the value being matched.
                                 //
-                                // FIXME: We don't actually  reads for ZSTs.
+                                // FIXME: We don't actually reads for ZSTs.
                                 needs_to_be_read = true;
                             }
                             _ => {
index 2cc7b357c0a466afdce888e0f5998f8e532e0771..943dc9b9646fc63131cd4f4394b0b530f7bbd978 100644 (file)
@@ -42,7 +42,7 @@ pub(super) fn type_inference_fallback(&self) {
         // We now see if we can make progress. This might cause us to
         // unify inference variables for opaque types, since we may
         // have unified some other type variables during the first
-        // phase of fallback.  This means that we only replace
+        // phase of fallback. This means that we only replace
         // inference variables with their underlying opaque types as a
         // last resort.
         //
@@ -76,7 +76,7 @@ pub(super) fn type_inference_fallback(&self) {
     //   (and the setting of `#![feature(never_type_fallback)]`).
     //
     // Fallback becomes very dubious if we have encountered
-    // type-checking errors.  In that case, fallback to Error.
+    // type-checking errors. In that case, fallback to Error.
     //
     // Sets `FnCtxt::fallback_has_occurred` if fallback is performed
     // during this call.
@@ -136,7 +136,7 @@ fn fallback_if_possible(
     /// constrained to have some other type).
     ///
     /// However, the fallback used to be `()` (before the `!` type was
-    /// added).  Moreover, there are cases where the `!` type 'leaks
+    /// added). Moreover, there are cases where the `!` type 'leaks
     /// out' from dead code into type variables that affect live
     /// code. The most common case is something like this:
     ///
@@ -149,7 +149,7 @@ fn fallback_if_possible(
     /// ```
     ///
     /// Here, coercing the type `!` into `?M` will create a diverging
-    /// type variable `?X` where `?X <: ?M`.  We also have that `?D <:
+    /// type variable `?X` where `?X <: ?M`. We also have that `?D <:
     /// ?M`. If `?M` winds up unconstrained, then `?X` will
     /// fallback. If it falls back to `!`, then all the type variables
     /// will wind up equal to `!` -- this includes the type `?D`
@@ -185,7 +185,7 @@ fn fallback_if_possible(
     ///
     /// The algorithm we use:
     /// * Identify all variables that are coerced *into* by a
-    ///   diverging variable.  Do this by iterating over each
+    ///   diverging variable. Do this by iterating over each
     ///   diverging, unsolved variable and finding all variables
     ///   reachable from there. Call that set `D`.
     /// * Walk over all unsolved, non-diverging variables, and find
@@ -196,8 +196,6 @@ fn calculate_diverging_fallback(
     ) -> FxHashMap<Ty<'tcx>, Ty<'tcx>> {
         debug!("calculate_diverging_fallback({:?})", unsolved_variables);
 
-        let relationships = self.fulfillment_cx.borrow_mut().relationships().clone();
-
         // Construct a coercion graph where an edge `A -> B` indicates
         // a type variable is that is coerced
         let coercion_graph = self.create_coercion_graph();
@@ -281,9 +279,7 @@ fn calculate_diverging_fallback(
             roots_reachable_from_non_diverging,
         );
 
-        debug!("inherited: {:#?}", self.inh.fulfillment_cx.borrow_mut().pending_obligations());
         debug!("obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations());
-        debug!("relationships: {:#?}", relationships);
 
         // For each diverging variable, figure out whether it can
         // reach a member of N. If so, it falls back to `()`. Else
@@ -297,16 +293,16 @@ fn calculate_diverging_fallback(
                 .depth_first_search(root_vid)
                 .any(|n| roots_reachable_from_non_diverging.visited(n));
 
-            let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false };
+            let mut found_infer_var_info = ty::InferVarInfo { self_in_trait: false, output: false };
 
-            for (vid, rel) in relationships.iter() {
-                if self.root_var(*vid) == root_vid {
-                    relationship.self_in_trait |= rel.self_in_trait;
-                    relationship.output |= rel.output;
+            for (vid, info) in self.inh.infer_var_info.borrow().iter() {
+                if self.infcx.root_var(*vid) == root_vid {
+                    found_infer_var_info.self_in_trait |= info.self_in_trait;
+                    found_infer_var_info.output |= info.output;
                 }
             }
 
-            if relationship.self_in_trait && relationship.output {
+            if found_infer_var_info.self_in_trait && found_infer_var_info.output {
                 // This case falls back to () to ensure that the code pattern in
                 // tests/ui/never_type/fallback-closure-ret.rs continues to
                 // compile when never_type_fallback is enabled.
index 8570715b41e59060d6ad2cbbb6e6aec20162c267..a355a54d6959abb5570144e9c40b53f2e973ce3f 100644 (file)
@@ -517,16 +517,72 @@ pub(in super::super) fn resolve_rvalue_scopes(&self, def_id: DefId) {
     }
 
     pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
+        if self.tcx.sess.opts.unstable_opts.drop_tracking_mir {
+            self.save_generator_interior_predicates(def_id);
+            return;
+        }
+
+        self.select_obligations_where_possible(|_| {});
+
         let mut generators = self.deferred_generator_interiors.borrow_mut();
-        for (body_id, interior, kind) in generators.drain(..) {
-            self.select_obligations_where_possible(|_| {});
+        for (_, body_id, interior, kind) in generators.drain(..) {
             crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
+            self.select_obligations_where_possible(|_| {});
+        }
+    }
+
+    /// Unify the inference variables corresponding to generator witnesses, and save all the
+    /// predicates that were stalled on those inference variables.
+    ///
+    /// This process allows to conservatively save all predicates that do depend on the generator
+    /// interior types, for later processing by `check_generator_obligations`.
+    ///
+    /// We must not attempt to select obligations after this method has run, or risk query cycle
+    /// ICE.
+    #[instrument(level = "debug", skip(self))]
+    fn save_generator_interior_predicates(&self, def_id: DefId) {
+        // Try selecting all obligations that are not blocked on inference variables.
+        // Once we start unifying generator witnesses, trying to select obligations on them will
+        // trigger query cycle ICEs, as doing so requires MIR.
+        self.select_obligations_where_possible(|_| {});
+
+        let generators = std::mem::take(&mut *self.deferred_generator_interiors.borrow_mut());
+        debug!(?generators);
+
+        for &(expr_def_id, body_id, interior, _) in generators.iter() {
+            debug!(?expr_def_id);
+
+            // Create the `GeneratorWitness` type that we will unify with `interior`.
+            let substs = ty::InternalSubsts::identity_for_item(
+                self.tcx,
+                self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
+            );
+            let witness = self.tcx.mk_generator_witness_mir(expr_def_id.to_def_id(), substs);
+
+            // Unify `interior` with `witness` and collect all the resulting obligations.
+            let span = self.tcx.hir().body(body_id).value.span;
+            let ok = self
+                .at(&self.misc(span), self.param_env)
+                .eq(interior, witness)
+                .expect("Failed to unify generator interior type");
+            let mut obligations = ok.obligations;
+
+            // Also collect the obligations that were unstalled by this unification.
+            obligations
+                .extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx));
+
+            let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause)).collect();
+            debug!(?obligations);
+            self.typeck_results
+                .borrow_mut()
+                .generator_interior_predicates
+                .insert(expr_def_id, obligations);
         }
     }
 
     #[instrument(skip(self), level = "debug")]
-    pub(in super::super) fn select_all_obligations_or_error(&self) {
-        let mut errors = self.fulfillment_cx.borrow_mut().select_all_or_error(&self);
+    pub(in super::super) fn report_ambiguity_errors(&self) {
+        let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors();
 
         if !errors.is_empty() {
             self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
@@ -926,43 +982,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")]
@@ -1224,9 +1243,7 @@ fn inferred_kind(
                     }
                     GenericParamDefKind::Const { has_default } => {
                         if !infer_args && has_default {
-                            tcx.bound_const_param_default(param.def_id)
-                                .subst(tcx, substs.unwrap())
-                                .into()
+                            tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
                         } else {
                             self.fcx.var_for_def(self.span, param)
                         }
index b9e13fd20092421554e9d9d3ce9899334f100d74..47ef106e750321470003d3b25103cbcb25b98d9c 100644 (file)
@@ -79,7 +79,7 @@ pub(in super::super) fn check_asms(&self) {
                 }
             };
             InlineAsmCtxt::new_in_fn(self.tcx, self.param_env, get_operand_ty)
-                .check_asm(asm, self.tcx.hir().local_def_id_to_hir_id(enclosing_id));
+                .check_asm(asm, enclosing_id);
         }
     }
 
@@ -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,13 +2141,12 @@ 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
                         // do that, so it's OK.
-                        for (predicate, span) in
-                            std::iter::zip(instantiated.predicates, instantiated.spans)
+                        for (predicate, span) in instantiated
                         {
                             if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = predicate.kind().skip_binder()
                                 && pred.self_ty().peel_refs() == callee_ty
index 428fde642bc0901bff4a7fb92c8c6cb6c589c100..4940015ddd571811d90137ce5dd33a69cd6ba08f 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(
@@ -324,6 +324,10 @@ fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
         let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty };
         self.write_ty(hir_id, ty)
     }
+
+    fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
+        Some(&self.infcx)
+    }
 }
 
 /// Represents a user-provided type in the raw form (never normalized).
index 005bd164065d80f612a6075c2f886957796a6bef..6046e55c65c18366c2b2cb10fae1cd1a390fe7f1 100644 (file)
@@ -11,7 +11,6 @@
     Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
 };
 use rustc_hir_analysis::astconv::AstConv;
-use rustc_infer::infer;
 use rustc_infer::traits::{self, StatementAsExpression};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
 use rustc_trait_selection::traits::error_reporting::DefIdOrName;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use rustc_trait_selection::traits::NormalizeExt;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     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()
     }
 
@@ -94,7 +93,7 @@ pub(crate) fn suggest_fn_call(
         found: Ty<'tcx>,
         can_satisfy: impl FnOnce(Ty<'tcx>) -> bool,
     ) -> bool {
-        let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(expr, found)
+        let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(found)
             else { return false; };
         if can_satisfy(output) {
             let (sugg_call, mut applicability) = match inputs.len() {
@@ -163,99 +162,10 @@ pub(crate) fn suggest_fn_call(
     /// because the callable type must also be well-formed to be called.
     pub(in super::super) fn extract_callable_info(
         &self,
-        expr: &Expr<'_>,
-        found: Ty<'tcx>,
+        ty: Ty<'tcx>,
     ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
-        // Autoderef is useful here because sometimes we box callables, etc.
-        let Some((def_id_or_name, output, inputs)) = self.autoderef(expr.span, found).silence_errors().find_map(|(found, _)| {
-            match *found.kind() {
-                ty::FnPtr(fn_sig) =>
-                    Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())),
-                ty::FnDef(def_id, _) => {
-                    let fn_sig = found.fn_sig(self.tcx);
-                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
-                }
-                ty::Closure(def_id, substs) => {
-                    let fn_sig = substs.as_closure().sig();
-                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
-                }
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
-                    self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
-                        if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
-                        && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
-                        // args tuple will always be substs[1]
-                        && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
-                        {
-                            Some((
-                                DefIdOrName::DefId(def_id),
-                                pred.kind().rebind(proj.term.ty().unwrap()),
-                                pred.kind().rebind(args.as_slice()),
-                            ))
-                        } else {
-                            None
-                        }
-                    })
-                }
-                ty::Dynamic(data, _, ty::Dyn) => {
-                    data.iter().find_map(|pred| {
-                        if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
-                        && Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
-                        // for existential projection, substs are shifted over by 1
-                        && let ty::Tuple(args) = proj.substs.type_at(0).kind()
-                        {
-                            Some((
-                                DefIdOrName::Name("trait object"),
-                                pred.rebind(proj.term.ty().unwrap()),
-                                pred.rebind(args.as_slice()),
-                            ))
-                        } else {
-                            None
-                        }
-                    })
-                }
-                ty::Param(param) => {
-                    let def_id = self.tcx.generics_of(self.body_id.owner).type_param(&param, self.tcx).def_id;
-                    self.tcx.predicates_of(self.body_id.owner).predicates.iter().find_map(|(pred, _)| {
-                        if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
-                        && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
-                        && proj.projection_ty.self_ty() == found
-                        // args tuple will always be substs[1]
-                        && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
-                        {
-                            Some((
-                                DefIdOrName::DefId(def_id),
-                                pred.kind().rebind(proj.term.ty().unwrap()),
-                                pred.kind().rebind(args.as_slice()),
-                            ))
-                        } else {
-                            None
-                        }
-                    })
-                }
-                _ => None,
-            }
-        }) else { return None; };
-
-        let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
-        let inputs = inputs
-            .skip_binder()
-            .iter()
-            .map(|ty| {
-                self.replace_bound_vars_with_fresh_vars(
-                    expr.span,
-                    infer::FnCall,
-                    inputs.rebind(*ty),
-                )
-            })
-            .collect();
-
-        // We don't want to register any extra obligations, which should be
-        // implied by wf, but also because that would possibly result in
-        // erroneous errors later on.
-        let infer::InferOk { value: output, obligations: _ } =
-            self.at(&self.misc(expr.span), self.param_env).normalize(output);
-
-        if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
+        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(
@@ -267,9 +177,9 @@ pub fn suggest_two_fn_call(
         rhs_ty: Ty<'tcx>,
         can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool,
     ) -> bool {
-        let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_expr, lhs_ty)
+        let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty)
             else { return false; };
-        let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_expr, rhs_ty)
+        let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_ty)
             else { return false; };
 
         if can_satisfy(lhs_output_ty, rhs_output_ty) {
@@ -452,7 +362,7 @@ pub fn suggest_deref_ref_or_into(
                             && method_call_list.contains(&conversion_method.name)
                             // If receiver is `.clone()` and found type has one of those methods,
                             // we guess that the user wants to convert from a slice type (`&[]` or `&str`)
-                            // to an owned type (`Vec` or `String`).  These conversions clone internally,
+                            // to an owned type (`Vec` or `String`). These conversions clone internally,
                             // so we remove the user's `clone` call.
                         {
                             vec![(
@@ -649,7 +559,7 @@ pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
                 }
             }
             ty::Adt(def, _) if def.is_box() && self.can_coerce(box_found, expected) => {
-                // Check if the parent expression is a call to Pin::new.  If it
+                // Check if the parent expression is a call to Pin::new. If it
                 // is and we were expecting a Box, ergo Pin<Box<expected>>, we
                 // can suggest Box::pin.
                 let parent = self.tcx.hir().parent_id(expr.hir_id);
index 15dd3412c34093e062eb5b74aa36a77fd5a3010a..38445f28440527822932e6424379d6419ddb46e5 100644 (file)
@@ -5,6 +5,7 @@
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::UserType;
+use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
 
@@ -156,7 +157,7 @@ fn visit_fn(
         _: &'tcx hir::FnDecl<'tcx>,
         _: hir::BodyId,
         _: Span,
-        _: hir::HirId,
+        _: LocalDefId,
     ) {
     }
 }
index 16806fdba4fbc2113c766be2ed489c032b5f1fda..b3dd3031db2a98d75780d00288364133be6041f4 100644 (file)
@@ -304,8 +304,8 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         let mut reinit = None;
         match expr.kind {
             ExprKind::Assign(lhs, rhs, _) => {
-                self.visit_expr(lhs);
                 self.visit_expr(rhs);
+                self.visit_expr(lhs);
 
                 reinit = Some(lhs);
             }
@@ -433,7 +433,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
                     self.drop_ranges.add_control_edge(self.expr_index, *target)
                 }),
 
-            ExprKind::Break(destination, ..) => {
+            ExprKind::Break(destination, value) => {
                 // destination either points to an expression or to a block. We use
                 // find_target_expression_from_destination to use the last expression of the block
                 // if destination points to a block.
@@ -443,7 +443,11 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
                 // will refer to the end of the block due to the post order traversal.
                 self.find_target_expression_from_destination(destination).map_or((), |target| {
                     self.drop_ranges.add_control_edge_hir_id(self.expr_index, target)
-                })
+                });
+
+                if let Some(value) = value {
+                    self.visit_expr(value);
+                }
             }
 
             ExprKind::Call(f, args) => {
@@ -465,6 +469,12 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
 
             ExprKind::AddrOf(..)
             | ExprKind::Array(..)
+            // FIXME(eholk): We probably need special handling for AssignOps. The ScopeTree builder
+            // in region.rs runs both lhs then rhs and rhs then lhs and then sets all yields to be
+            // the latest they show up in either traversal. With the older scope-based
+            // approximation, this was fine, but it's probably not right now. What we probably want
+            // to do instead is still run both orders, but consider anything that showed up as a
+            // yield in either order.
             | ExprKind::AssignOp(..)
             | ExprKind::Binary(..)
             | ExprKind::Block(..)
@@ -502,6 +512,9 @@ fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
 
         // Increment expr_count here to match what InteriorVisitor expects.
         self.expr_index = self.expr_index + 1;
+
+        // Save a node mapping to get better CFG visualization
+        self.drop_ranges.add_node_mapping(pat.hir_id, self.expr_index);
     }
 }
 
@@ -521,7 +534,7 @@ fn new(
                 }
             });
         }
-        debug!("hir_id_map: {:?}", tracked_value_map);
+        debug!("hir_id_map: {:#?}", tracked_value_map);
         let num_values = tracked_value_map.len();
         Self {
             tracked_value_map,
index c0a0bfe8e1c00a98cb53dd41b5d1e6e9bb7ba82c..e8d31be79d9c9fccff6d6722db6cadf044cbb7a8 100644 (file)
@@ -2,6 +2,7 @@
 //! flow graph when needed for debugging.
 
 use rustc_graphviz as dot;
+use rustc_hir::{Expr, ExprKind, Node};
 use rustc_middle::ty::TyCtxt;
 
 use super::{DropRangesBuilder, PostOrderId};
@@ -80,10 +81,14 @@ fn node_label(&'a self, n: &Self::Node) -> dot::LabelText<'a> {
                     .post_order_map
                     .iter()
                     .find(|(_hir_id, &post_order_id)| post_order_id == *n)
-                    .map_or("<unknown>".into(), |(hir_id, _)| self
-                        .tcx
-                        .hir()
-                        .node_to_string(*hir_id))
+                    .map_or("<unknown>".into(), |(hir_id, _)| format!(
+                        "{}{}",
+                        self.tcx.hir().node_to_string(*hir_id),
+                        match self.tcx.hir().find(*hir_id) {
+                            Some(Node::Expr(Expr { kind: ExprKind::Yield(..), .. })) => " (yield)",
+                            _ => "",
+                        }
+                    ))
             )
             .into(),
         )
index 472205be7b5e3e81a96f1438b97d6865a691786c..ed3d890315704cefd1f2932e62b3f3e30a6c47e8 100644 (file)
@@ -116,7 +116,7 @@ fn borrow_place(&mut self, place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx
         // where the `identity(...)` (the rvalue) produces a return type
         // of `&'rv mut A`, where `'a: 'rv`. We then assign this result to
         // `'y`, resulting in (transitively) `'a: 'y` (i.e., while `y` is in use,
-        // `a` will be considered borrowed).  Other parts of the code will ensure
+        // `a` will be considered borrowed). Other parts of the code will ensure
         // that if `y` is live over a yield, `&'y mut A` appears in the generator
         // state. If `'y` is live, then any sound region analysis must conclude
         // that `'a` is also live. So if this causes a bug, blame some other
index 7990d95310be59489989d8d4753c74b39aaa7eb1..7af5260538568c0d873ad2767cdbb903e5a6517e 100644 (file)
@@ -71,10 +71,8 @@ fn record(
                                 yield_data.expr_and_pat_count, self.expr_count, source_span
                             );
 
-                            if self.fcx.sess().opts.unstable_opts.drop_tracking
-                                && self
-                                    .drop_ranges
-                                    .is_dropped_at(hir_id, yield_data.expr_and_pat_count)
+                            if self
+                                .is_dropped_at_yield_location(hir_id, yield_data.expr_and_pat_count)
                             {
                                 debug!("value is dropped at yield point; not recording");
                                 return false;
@@ -173,6 +171,18 @@ fn record(
             }
         }
     }
+
+    /// If drop tracking is enabled, consult drop_ranges to see if a value is
+    /// known to be dropped at a yield point and therefore can be omitted from
+    /// the generator witness.
+    fn is_dropped_at_yield_location(&self, value_hir_id: HirId, yield_location: usize) -> bool {
+        // short-circuit if drop tracking is not enabled.
+        if !self.fcx.sess().opts.unstable_opts.drop_tracking {
+            return false;
+        }
+
+        self.drop_ranges.is_dropped_at(value_hir_id, yield_location)
+    }
 }
 
 pub fn resolve_interior<'a, 'tcx>(
index b33e7b8d68cf927251a4e85a9c57a672fcabf9b5..87e54025330e8a928873fc3295a31dd5e17d1a78 100644 (file)
@@ -1,6 +1,6 @@
 use super::callee::DeferredCallResolution;
 
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::HirIdMap;
@@ -10,7 +10,8 @@
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefIdMap;
 use rustc_span::{self, Span};
-use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _};
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::{self, PredicateObligation, TraitEngine, TraitEngineExt as _};
 
 use std::cell::RefCell;
 use std::ops::Deref;
@@ -55,7 +56,7 @@ pub struct Inherited<'tcx> {
     pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, hir::HirId)>>,
 
     pub(super) deferred_generator_interiors:
-        RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
+        RefCell<Vec<(LocalDefId, hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
 
     pub(super) body_id: Option<hir::BodyId>,
 
@@ -63,6 +64,8 @@ pub struct Inherited<'tcx> {
     /// we record that type variable here. This is later used to inform
     /// fallback. See the `fallback` module for details.
     pub(super) diverging_type_vars: RefCell<FxHashSet<Ty<'tcx>>>,
+
+    pub(super) infer_var_info: RefCell<FxHashMap<ty::TyVid, ty::InferVarInfo>>,
 }
 
 impl<'tcx> Deref for Inherited<'tcx> {
@@ -128,6 +131,7 @@ fn new(
             deferred_generator_interiors: RefCell::new(Vec::new()),
             diverging_type_vars: RefCell::new(Default::default()),
             body_id,
+            infer_var_info: RefCell::new(Default::default()),
         }
     }
 
@@ -136,6 +140,9 @@ pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<
         if obligation.has_escaping_bound_vars() {
             span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
         }
+
+        self.update_infer_var_info(&obligation);
+
         self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation);
     }
 
@@ -152,4 +159,43 @@ pub(super) fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>
         self.register_predicates(infer_ok.obligations);
         infer_ok.value
     }
+
+    pub fn update_infer_var_info(&self, obligation: &PredicateObligation<'tcx>) {
+        let infer_var_info = &mut self.infer_var_info.borrow_mut();
+
+        // (*) binder skipped
+        if let ty::PredicateKind::Clause(ty::Clause::Trait(tpred)) = obligation.predicate.kind().skip_binder()
+            && let Some(ty) = self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t))
+            && self.tcx.lang_items().sized_trait().map_or(false, |st| st != tpred.trait_ref.def_id)
+        {
+            let new_self_ty = self.tcx.types.unit;
+
+            // Then construct a new obligation with Self = () added
+            // to the ParamEnv, and see if it holds.
+            let o = obligation.with(self.tcx,
+                obligation
+                    .predicate
+                    .kind()
+                    .rebind(
+                        // (*) binder moved here
+                        ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_ty(self.tcx, new_self_ty)))
+                    ),
+            );
+            // Don't report overflow errors. Otherwise equivalent to may_hold.
+            if let Ok(result) = self.probe(|_| self.evaluate_obligation(&o)) && result.may_apply() {
+                infer_var_info.entry(ty).or_default().self_in_trait = true;
+            }
+        }
+
+        if let ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) =
+            obligation.predicate.kind().skip_binder()
+        {
+            // If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
+            // we need to make it into one.
+            if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
+                debug!("infer_var_info: {:?}.output = true", vid);
+                infer_var_info.entry(vid).or_default().output = true;
+            }
+        }
+    }
 }
index c2dc14024655aeba39308b9efad08977356f5580..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}"))
@@ -105,6 +106,16 @@ pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
         } else {
             err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
                 .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
+            let mut should_delay_as_bug = false;
+            if let Err(LayoutError::Unknown(bad_from)) = sk_from && bad_from.references_error() {
+                should_delay_as_bug = true;
+            }
+            if let Err(LayoutError::Unknown(bad_to)) = sk_to && bad_to.references_error() {
+                should_delay_as_bug = true;
+            }
+            if should_delay_as_bug {
+                err.delay_as_bug();
+            }
         }
         err.emit();
     }
index 7ddf9eaa4d8995463fa730d5ad653c536b174d2b..323bacf70ab9ca911b5f34c5619eb6c41b0828d6 100644 (file)
@@ -201,13 +201,13 @@ 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() {
                 fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
             } else {
-                tcx.fn_sig(def_id)
+                tcx.fn_sig(def_id).subst_identity()
             };
 
             check_abi(tcx, id, span, fn_sig.abi());
@@ -294,14 +294,24 @@ fn typeck_with_fallback<'tcx>(
         // Before the generator analysis, temporary scopes shall be marked to provide more
         // precise information on types to be captured.
         fcx.resolve_rvalue_scopes(def_id.to_def_id());
-        fcx.resolve_generator_interiors(def_id.to_def_id());
 
         for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
             let ty = fcx.normalize(span, ty);
             fcx.require_type_is_sized(ty, span, code);
         }
 
-        fcx.select_all_obligations_or_error();
+        fcx.select_obligations_where_possible(|_| {});
+
+        debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
+
+        // This must be the last thing before `report_ambiguity_errors`.
+        fcx.resolve_generator_interiors(def_id.to_def_id());
+
+        debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
+
+        if let None = fcx.infcx.tainted_by_errors() {
+            fcx.report_ambiguity_errors();
+        }
 
         if let None = fcx.infcx.tainted_by_errors() {
             fcx.check_transmutes();
index 0b5dc946c1deffa589f20f036542cfacc7edd6a8..48c75cde9a5fc544948e231ea4077a86ad698f9d 100644 (file)
@@ -736,7 +736,7 @@ fn cat_pattern_<F>(
             }
 
             PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) => {
-                // box p1, &p1, &mut p1.  we can ignore the mutability of
+                // box p1, &p1, &mut p1. we can ignore the mutability of
                 // PatKind::Ref since that information is already contained
                 // in the type.
                 let subplace = self.cat_deref(pat, place_with_id)?;
index 4a33a791e1b7f3b12db9c6e54ca541ab93b5c0fa..65ca47bfe538bbd5c42cb8854ee9dfa1adcc601b 100644 (file)
@@ -19,7 +19,6 @@
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::traits;
 
-use std::iter;
 use std::ops::Deref;
 
 struct ConfirmContext<'a, 'tcx> {
@@ -101,7 +100,7 @@ fn confirm(
         let filler_substs = rcvr_substs
             .extend_to(self.tcx, pick.item.def_id, |def, _| self.tcx.mk_param_from_def(def));
         let illegal_sized_bound = self.predicates_require_illegal_sized_bound(
-            &self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs),
+            self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs),
         );
 
         // Unify the (adjusted) self type with what the method expects.
@@ -504,9 +503,7 @@ fn instantiate_method_sig(
 
         debug!("method_predicates after subst = {:?}", method_predicates);
 
-        let sig = self.tcx.bound_fn_sig(def_id);
-
-        let sig = sig.subst(self.tcx, all_substs);
+        let sig = self.tcx.fn_sig(def_id).subst(self.tcx, all_substs);
         debug!("type scheme substituted, sig={:?}", sig);
 
         let sig = self.replace_bound_vars_with_fresh_vars(sig);
@@ -565,7 +562,7 @@ fn add_obligations(
 
     fn predicates_require_illegal_sized_bound(
         &self,
-        predicates: &ty::InstantiatedPredicates<'tcx>,
+        predicates: ty::InstantiatedPredicates<'tcx>,
     ) -> Option<Span> {
         let sized_def_id = self.tcx.lang_items().sized_trait()?;
 
@@ -575,10 +572,11 @@ fn predicates_require_illegal_sized_bound(
                 ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
                     if trait_pred.def_id() == sized_def_id =>
                 {
-                    let span = iter::zip(&predicates.predicates, &predicates.spans)
+                    let span = predicates
+                        .iter()
                         .find_map(
                             |(p, span)| {
-                                if *p == obligation.predicate { Some(*span) } else { None }
+                                if p == obligation.predicate { Some(span) } else { None }
                             },
                         )
                         .unwrap_or(rustc_span::DUMMY_SP);
index 146d5e60c2f388c2bfd7257c66af6b91414ed12f..60d4dc326eea16f837983767fc138d6ffda50a5d 100644 (file)
@@ -76,7 +76,7 @@ pub struct NoMatchData<'tcx> {
     pub unsatisfied_predicates:
         Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
     pub out_of_scope_traits: Vec<DefId>,
-    pub lev_candidate: Option<ty::AssocItem>,
+    pub similar_candidate: Option<ty::AssocItem>,
     pub mode: probe::Mode,
 }
 
@@ -145,7 +145,7 @@ pub(crate) fn suggest_method_call(
             )
             .map(|pick| {
                 let sig = self.tcx.fn_sig(pick.item.def_id);
-                sig.inputs().skip_binder().len().saturating_sub(1)
+                sig.skip_binder().inputs().skip_binder().len().saturating_sub(1)
             })
             .unwrap_or(0);
 
@@ -399,8 +399,7 @@ fn construct_obligation_for_trait(
         // N.B., instantiate late-bound regions before normalizing the
         // function signature so that normalization does not need to deal
         // with bound regions.
-        let fn_sig = tcx.bound_fn_sig(def_id);
-        let fn_sig = fn_sig.subst(self.tcx, substs);
+        let fn_sig = tcx.fn_sig(def_id).subst(self.tcx, substs);
         let fn_sig =
             self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
 
@@ -413,7 +412,7 @@ fn construct_obligation_for_trait(
 
         // Register obligations for the parameters. This will include the
         // `Self` parameter, which in turn has a bound of the main trait,
-        // so this also effectively registers `obligation` as well.  (We
+        // so this also effectively registers `obligation` as well. (We
         // used to register `obligation` explicitly, but that resulted in
         // double error messages being reported.)
         //
index dd827777df94e68c03c031b98af1594b06e72793..9fc4c16fb071d2dbac212436a8187cca2d836a2a 100644 (file)
@@ -232,7 +232,7 @@ pub enum PickKind<'tcx> {
 pub enum Mode {
     // An expression of the form `receiver.method_name(...)`.
     // Autoderefs are performed on `receiver`, lookup is done based on the
-    // `self` argument  of the method, and static methods aren't considered.
+    // `self` argument of the method, and static methods aren't considered.
     MethodCall,
     // An expression of the form `Type::item` or `<T>::item`.
     // No autoderefs are performed, lookup is done based on the type each
@@ -461,7 +461,7 @@ fn probe_op<OP, R>(
                     static_candidates: Vec::new(),
                     unsatisfied_predicates: Vec::new(),
                     out_of_scope_traits: Vec::new(),
-                    lev_candidate: None,
+                    similar_candidate: None,
                     mode,
                 }));
             }
@@ -486,7 +486,7 @@ fn probe_op<OP, R>(
             probe_cx.assemble_inherent_candidates();
             match scope {
                 ProbeScope::TraitsInScope => {
-                    probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)
+                    probe_cx.assemble_extension_candidates_for_traits_in_scope()
                 }
                 ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits(),
             };
@@ -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
@@ -889,9 +889,9 @@ fn elaborate_bounds<F>(
         }
     }
 
-    fn assemble_extension_candidates_for_traits_in_scope(&mut self, expr_hir_id: hir::HirId) {
+    fn assemble_extension_candidates_for_traits_in_scope(&mut self) {
         let mut duplicates = FxHashSet::default();
-        let opt_applicable_traits = self.tcx.in_scope_traits(expr_hir_id);
+        let opt_applicable_traits = self.tcx.in_scope_traits(self.scope_expr_id);
         if let Some(applicable_traits) = opt_applicable_traits {
             for trait_candidate in applicable_traits.iter() {
                 let trait_did = trait_candidate.def_id;
@@ -921,26 +921,22 @@ fn matches_return_type(
         expected: Ty<'tcx>,
     ) -> bool {
         match method.kind {
-            ty::AssocKind::Fn => {
-                let fty = self.tcx.bound_fn_sig(method.def_id);
-                self.probe(|_| {
-                    let substs = self.fresh_substs_for_item(self.span, method.def_id);
-                    let fty = fty.subst(self.tcx, substs);
-                    let fty =
-                        self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty);
-
-                    if let Some(self_ty) = self_ty {
-                        if self
-                            .at(&ObligationCause::dummy(), self.param_env)
-                            .sup(fty.inputs()[0], self_ty)
-                            .is_err()
-                        {
-                            return false;
-                        }
+            ty::AssocKind::Fn => self.probe(|_| {
+                let substs = self.fresh_substs_for_item(self.span, method.def_id);
+                let fty = self.tcx.fn_sig(method.def_id).subst(self.tcx, substs);
+                let fty = self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty);
+
+                if let Some(self_ty) = self_ty {
+                    if self
+                        .at(&ObligationCause::dummy(), self.param_env)
+                        .sup(fty.inputs()[0], self_ty)
+                        .is_err()
+                    {
+                        return false;
                     }
-                    self.can_sub(self.param_env, fty.output(), expected).is_ok()
-                })
-            }
+                }
+                self.can_sub(self.param_env, fty.output(), expected).is_ok()
+            }),
             _ => false,
         }
     }
@@ -1076,13 +1072,13 @@ fn pick(mut self) -> PickResult<'tcx> {
         if let Some((kind, def_id)) = private_candidate {
             return Err(MethodError::PrivateMatch(kind, def_id, out_of_scope_traits));
         }
-        let lev_candidate = self.probe_for_lev_candidate()?;
+        let similar_candidate = self.probe_for_similar_candidate()?;
 
         Err(MethodError::NoMatch(NoMatchData {
             static_candidates,
             unsatisfied_predicates,
             out_of_scope_traits,
-            lev_candidate,
+            similar_candidate,
             mode: self.mode,
         }))
     }
@@ -1587,11 +1583,29 @@ fn consider_probe(
                         let o = self.resolve_vars_if_possible(o);
                         if !self.predicate_may_hold(&o) {
                             result = ProbeResult::NoMatch;
-                            possibly_unsatisfied_predicates.push((
-                                o.predicate,
-                                None,
-                                Some(o.cause),
-                            ));
+                            let parent_o = o.clone();
+                            let implied_obligations =
+                                traits::elaborate_obligations(self.tcx, vec![o]);
+                            for o in implied_obligations {
+                                let parent = if o == parent_o {
+                                    None
+                                } else {
+                                    if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id())
+                                        == self.tcx.lang_items().sized_trait()
+                                    {
+                                        // We don't care to talk about implicit `Sized` bounds.
+                                        continue;
+                                    }
+                                    Some(parent_o.predicate)
+                                };
+                                if !self.predicate_may_hold(&o) {
+                                    possibly_unsatisfied_predicates.push((
+                                        o.predicate,
+                                        parent,
+                                        Some(o.cause),
+                                    ));
+                                }
+                            }
                         }
                     }
                 }
@@ -1769,7 +1783,7 @@ fn collapse_candidates_to_trait_pick(
     /// Similarly to `probe_for_return_type`, this method attempts to find the best matching
     /// candidate method where the method name may have been misspelled. Similarly to other
     /// Levenshtein based suggestions, we provide at most one such suggestion.
-    fn probe_for_lev_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> {
+    fn probe_for_similar_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> {
         debug!("probing for method names similar to {:?}", self.method_name);
 
         let steps = self.steps.clone();
@@ -1813,6 +1827,12 @@ fn probe_for_lev_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodErr
                         None,
                     )
                 }
+                .or_else(|| {
+                    applicable_close_candidates
+                        .iter()
+                        .find(|cand| self.matches_by_doc_alias(cand.def_id))
+                        .map(|cand| cand.name)
+                })
                 .unwrap();
                 Ok(applicable_close_candidates.into_iter().find(|method| method.name == best_name))
             }
@@ -1863,7 +1883,7 @@ fn xform_self_ty(
 
     #[instrument(level = "debug", skip(self))]
     fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> {
-        let fn_sig = self.tcx.bound_fn_sig(method);
+        let fn_sig = self.tcx.fn_sig(method);
         debug!(?fn_sig);
 
         assert!(!substs.has_escaping_bound_vars());
@@ -1963,6 +1983,38 @@ fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool {
         }
     }
 
+    /// Determine if the associated item withe the given DefId matches
+    /// the desired name via a doc alias.
+    fn matches_by_doc_alias(&self, def_id: DefId) -> bool {
+        let Some(name) = self.method_name else { return false; };
+        let Some(local_def_id) = def_id.as_local() else { return false; };
+        let hir_id = self.fcx.tcx.hir().local_def_id_to_hir_id(local_def_id);
+        let attrs = self.fcx.tcx.hir().attrs(hir_id);
+        for attr in attrs {
+            let sym::doc = attr.name_or_empty() else { continue; };
+            let Some(values) = attr.meta_item_list() else { continue; };
+            for v in values {
+                if v.name_or_empty() != sym::alias {
+                    continue;
+                }
+                if let Some(nested) = v.meta_item_list() {
+                    // #[doc(alias("foo", "bar"))]
+                    for n in nested {
+                        if let Some(lit) = n.lit() && name.as_str() == lit.symbol.as_str() {
+                            return true;
+                        }
+                    }
+                } else if let Some(meta) = v.meta_item()
+                    && let Some(lit) = meta.name_value_literal()
+                    && name.as_str() == lit.symbol.as_str() {
+                        // #[doc(alias = "foo")]
+                        return true;
+                }
+            }
+        }
+        false
+    }
+
     /// Finds the method with the appropriate name (or return type, as the case may be). If
     /// `allow_similar_names` is set, find methods with close-matching names.
     // The length of the returned iterator is nearly always 0 or 1 and this
@@ -1978,6 +2030,9 @@ fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool {
                         if !self.is_relevant_kind_for_mode(x.kind) {
                             return false;
                         }
+                        if self.matches_by_doc_alias(x.def_id) {
+                            return true;
+                        }
                         match lev_distance_with_substrings(name.as_str(), x.name.as_str(), max_dist)
                         {
                             Some(d) => d > 0,
index 8166eb8299041136a089eb92866cf4fea044dd0b..31d55a41d8a31b6d91b3d533d95a2008ab0b87ad 100644 (file)
@@ -262,7 +262,7 @@ pub fn report_no_match_method_error(
         let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
         let is_method = mode == Mode::MethodCall;
         let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
-        let lev_candidate = no_match_data.lev_candidate;
+        let similar_candidate = no_match_data.similar_candidate;
         let item_kind = if is_method {
             "method"
         } else if rcvr_ty.is_enum() {
@@ -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,28 +495,28 @@ 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))
                             }
                             _ => None,
                         };
-                        if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
-                            if let Some(g) = kind.generics() {
-                                let key = (
-                                    g.tail_span_for_predicate_suggestion(),
-                                    g.add_where_or_trailing_comma(),
-                                );
-                                type_params
-                                    .entry(key)
-                                    .or_insert_with(FxHashSet::default)
-                                    .insert(obligation.to_owned());
-                            }
+                        if let Some(hir::Node::Item(hir::Item { kind, .. })) = node
+                            && let Some(g) = kind.generics()
+                        {
+                            let key = (
+                                g.tail_span_for_predicate_suggestion(),
+                                g.add_where_or_trailing_comma(),
+                            );
+                            type_params
+                                .entry(key)
+                                .or_insert_with(FxHashSet::default)
+                                .insert(obligation.to_owned());
+                            return true;
                         }
                     }
+                    false
                 };
             let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
                 let msg = format!(
@@ -692,7 +691,20 @@ pub fn report_no_match_method_error(
                             "auto trait is invoked with no method error, but no error reported?",
                         );
                     }
-                    Some(_) => unreachable!(),
+                    Some(Node::Item(hir::Item {
+                        ident, kind: hir::ItemKind::Trait(..), ..
+                    })) => {
+                        skip_list.insert(p);
+                        let entry = spanned_predicates.entry(ident.span);
+                        let entry = entry.or_insert_with(|| {
+                            (FxHashSet::default(), FxHashSet::default(), Vec::new())
+                        });
+                        entry.0.insert(cause.span);
+                        entry.1.insert((ident.span, ""));
+                        entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
+                        entry.2.push(p);
+                    }
+                    Some(node) => unreachable!("encountered `{node:?}`"),
                     None => (),
                 }
             }
@@ -719,19 +731,39 @@ pub fn report_no_match_method_error(
                 unsatisfied_bounds = true;
             }
 
+            let mut suggested_bounds = FxHashSet::default();
             // The requirements that didn't have an `impl` span to show.
             let mut bound_list = unsatisfied_predicates
                 .iter()
                 .filter_map(|(pred, parent_pred, _cause)| {
+                    let mut suggested = false;
                     format_pred(*pred).map(|(p, self_ty)| {
-                        collect_type_param_suggestions(self_ty, *pred, &p);
+                        if let Some(parent) = parent_pred && suggested_bounds.contains(parent) {
+                            // We don't suggest `PartialEq` when we already suggest `Eq`.
+                        } else if !suggested_bounds.contains(pred) {
+                            if collect_type_param_suggestions(self_ty, *pred, &p) {
+                                suggested = true;
+                                suggested_bounds.insert(pred);
+                            }
+                        }
                         (
                             match parent_pred {
                                 None => format!("`{}`", &p),
                                 Some(parent_pred) => match format_pred(*parent_pred) {
                                     None => format!("`{}`", &p),
                                     Some((parent_p, _)) => {
-                                        collect_type_param_suggestions(self_ty, *parent_pred, &p);
+                                        if !suggested
+                                            && !suggested_bounds.contains(pred)
+                                            && !suggested_bounds.contains(parent_pred)
+                                        {
+                                            if collect_type_param_suggestions(
+                                                self_ty,
+                                                *parent_pred,
+                                                &p,
+                                            ) {
+                                                suggested_bounds.insert(pred);
+                                            }
+                                        }
                                         format!("`{}`\nwhich is required by `{}`", p, parent_p)
                                     }
                                 },
@@ -902,7 +934,7 @@ trait bound{s}",
         // give a helping note that it has to be called as `(x.f)(...)`.
         if let SelfSource::MethodCall(expr) = source {
             if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
-                && lev_candidate.is_none()
+                && similar_candidate.is_none()
                 && !custom_span_label
             {
                 label_span_not_found(&mut err);
@@ -980,20 +1012,20 @@ trait bound{s}",
             if fallback_span {
                 err.span_label(span, msg);
             }
-        } else if let Some(lev_candidate) = lev_candidate {
+        } else if let Some(similar_candidate) = similar_candidate {
             // Don't emit a suggestion if we found an actual method
             // that had unsatisfied trait bounds
             if unsatisfied_predicates.is_empty() {
-                let def_kind = lev_candidate.kind.as_def_kind();
+                let def_kind = similar_candidate.kind.as_def_kind();
                 // Methods are defined within the context of a struct and their first parameter is always self,
                 // which represents the instance of the struct the method is being called on
                 // Associated functions don’t take self as a parameter and
                 // they are not methods because they don’t have an instance of the struct to work with.
-                if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
+                if def_kind == DefKind::AssocFn && similar_candidate.fn_has_self_parameter {
                     err.span_suggestion(
                         span,
                         "there is a method with a similar name",
-                        lev_candidate.name,
+                        similar_candidate.name,
                         Applicability::MaybeIncorrect,
                     );
                 } else {
@@ -1002,9 +1034,9 @@ trait bound{s}",
                         &format!(
                             "there is {} {} with a similar name",
                             def_kind.article(),
-                            def_kind.descr(lev_candidate.def_id),
+                            def_kind.descr(similar_candidate.def_id),
                         ),
-                        lev_candidate.name,
+                        similar_candidate.name,
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -1037,7 +1069,7 @@ fn note_candidates_on_method_error(
                     // the impl, if local to crate (item may be defaulted), else nothing.
                     let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
                         let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
-                        self.associated_value(impl_trait_ref.def_id, item_name)
+                        self.associated_value(impl_trait_ref.skip_binder().def_id, item_name)
                     }) else {
                         continue;
                     };
@@ -1055,7 +1087,10 @@ fn note_candidates_on_method_error(
                     let insertion = match self.tcx.impl_trait_ref(impl_did) {
                         None => String::new(),
                         Some(trait_ref) => {
-                            format!(" of the trait `{}`", self.tcx.def_path_str(trait_ref.def_id))
+                            format!(
+                                " of the trait `{}`",
+                                self.tcx.def_path_str(trait_ref.skip_binder().def_id)
+                            )
                         }
                     };
 
@@ -1086,13 +1121,14 @@ fn note_candidates_on_method_error(
                     }
                     if let Some(sugg_span) = sugg_span
                         && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
-                        let path = self.tcx.def_path_str(trait_ref.def_id);
+                        let path = self.tcx.def_path_str(trait_ref.skip_binder().def_id);
 
                         let ty = match item.kind {
                             ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
                             ty::AssocKind::Fn => self
                                 .tcx
                                 .fn_sig(item.def_id)
+                                .subst_identity()
                                 .inputs()
                                 .skip_binder()
                                 .get(0)
@@ -1229,7 +1265,7 @@ fn suggest_associated_call_syntax(
                 && let Some(assoc) = self.associated_value(*impl_did, item_name)
                 && assoc.kind == ty::AssocKind::Fn
             {
-                let sig = self.tcx.fn_sig(assoc.def_id);
+                let sig = self.tcx.fn_sig(assoc.def_id).subst_identity();
                 sig.inputs().skip_binder().get(0).and_then(|first| if first.peel_refs() == rcvr_ty.peel_refs() {
                     None
                 } else {
@@ -1305,7 +1341,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 {
@@ -1555,7 +1591,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,
@@ -2062,7 +2099,7 @@ fn check_for_deref_method(
                     // just changing the path.
                     && pick.item.fn_has_self_parameter
                     && let Some(self_ty) =
-                        self.tcx.fn_sig(pick.item.def_id).inputs().skip_binder().get(0)
+                        self.tcx.fn_sig(pick.item.def_id).subst_identity().inputs().skip_binder().get(0)
                     && self_ty.is_ref()
                 {
                     let suggested_path = match deref_ty.kind() {
@@ -2157,7 +2194,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;
 
@@ -2315,7 +2352,7 @@ fn suggest_traits_to_import(
                         // implement the `AsRef` trait.
                         let skip = skippable.contains(&did)
                             || (("Pin::new" == *pre) && (sym::as_ref == item_name.name))
-                            || inputs_len.map_or(false, |inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().inputs().len() != inputs_len);
+                            || inputs_len.map_or(false, |inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() != inputs_len);
                         // Make sure the method is defined for the *actual* receiver: we don't
                         // want to treat `Box<Self>` as a receiver if it only works because of
                         // an autoderef to `&self`
@@ -2479,7 +2516,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() {
@@ -2581,7 +2618,7 @@ enum Introducer {
                             self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative
                         })
                         .any(|imp_did| {
-                            let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
+                            let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
                             let imp_simp =
                                 simplify_type(self.tcx, imp.self_ty(), TreatParams::AsPlaceholder);
                             imp_simp.map_or(false, |s| s == simp_rcvr_ty)
@@ -2662,8 +2699,10 @@ pub(crate) fn suggest_else_fn_with_closure(
         found: Ty<'tcx>,
         expected: Ty<'tcx>,
     ) -> bool {
-        let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(expr, found)
-        else { return false; };
+        let Some((_def_id_or_name, output, _inputs)) =
+            self.extract_callable_info(found) else {
+                return false;
+        };
 
         if !self.can_coerce(output, expected) {
             return false;
@@ -2693,7 +2732,7 @@ pub(crate) fn suggest_else_fn_with_closure(
             // check the method arguments number
             if let Ok(pick) = probe &&
                 let fn_sig = self.tcx.fn_sig(pick.item.def_id) &&
-                let fn_args = fn_sig.skip_binder().inputs() &&
+                let fn_args = fn_sig.skip_binder().skip_binder().inputs() &&
                 fn_args.len() == args.len() + 1 {
                 err.span_suggestion_verbose(
                     method_name.span.shrink_to_hi(),
index 8c24b6006444a8dc26d21d57b009768b05a0ad82..0aa34f9dd70724d2b0588fec4de21bbe150d0b57 100644 (file)
@@ -40,8 +40,7 @@ pub fn resolve_type_vars_in_body(
         &self,
         body: &'tcx hir::Body<'tcx>,
     ) -> &'tcx ty::TypeckResults<'tcx> {
-        let item_id = self.tcx.hir().body_owner(body.id());
-        let item_def_id = self.tcx.hir().local_def_id(item_id);
+        let item_def_id = self.tcx.hir().body_owner_def_id(body.id());
 
         // This attribute causes us to dump some writeback information
         // in the form of errors, which is used for unit tests.
@@ -55,7 +54,8 @@ pub fn resolve_type_vars_in_body(
         // Type only exists for constants and statics, not functions.
         match self.tcx.hir().body_owner_kind(item_def_id) {
             hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => {
-                wbcx.visit_node_id(body.value.span, item_id);
+                let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(item_def_id);
+                wbcx.visit_node_id(body.value.span, item_hir_id);
             }
             hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (),
         }
@@ -448,8 +448,11 @@ fn visit_closures(&mut self) {
         assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
         let common_hir_owner = fcx_typeck_results.hir_owner;
 
-        for (id, origin) in fcx_typeck_results.closure_kind_origins().iter() {
-            let hir_id = hir::HirId { owner: common_hir_owner, local_id: *id };
+        let fcx_closure_kind_origins =
+            fcx_typeck_results.closure_kind_origins().items_in_stable_order();
+
+        for (local_id, origin) in fcx_closure_kind_origins {
+            let hir_id = hir::HirId { owner: common_hir_owner, local_id };
             let place_span = origin.0;
             let place = self.resolve(origin.1.clone(), &place_span);
             self.typeck_results.closure_kind_origins_mut().insert(hir_id, (place_span, place));
@@ -458,11 +461,12 @@ fn visit_closures(&mut self) {
 
     fn visit_coercion_casts(&mut self) {
         let fcx_typeck_results = self.fcx.typeck_results.borrow();
-        let fcx_coercion_casts = fcx_typeck_results.coercion_casts();
+
         assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
 
+        let fcx_coercion_casts = fcx_typeck_results.coercion_casts().to_sorted_stable_ord();
         for local_id in fcx_coercion_casts {
-            self.typeck_results.set_coercion_cast(*local_id);
+            self.typeck_results.set_coercion_cast(local_id);
         }
     }
 
@@ -471,22 +475,15 @@ fn visit_user_provided_tys(&mut self) {
         assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
         let common_hir_owner = fcx_typeck_results.hir_owner;
 
-        let mut errors_buffer = Vec::new();
-        for (&local_id, c_ty) in fcx_typeck_results.user_provided_types().iter() {
-            let hir_id = hir::HirId { owner: common_hir_owner, local_id };
-
-            if cfg!(debug_assertions) && c_ty.needs_infer() {
-                span_bug!(
-                    hir_id.to_span(self.fcx.tcx),
-                    "writeback: `{:?}` has inference variables",
-                    c_ty
-                );
-            };
+        if self.rustc_dump_user_substs {
+            let sorted_user_provided_types =
+                fcx_typeck_results.user_provided_types().items_in_stable_order();
 
-            self.typeck_results.user_provided_types_mut().insert(hir_id, *c_ty);
+            let mut errors_buffer = Vec::new();
+            for (local_id, c_ty) in sorted_user_provided_types {
+                let hir_id = hir::HirId { owner: common_hir_owner, local_id };
 
-            if let ty::UserType::TypeOf(_, user_substs) = c_ty.value {
-                if self.rustc_dump_user_substs {
+                if let ty::UserType::TypeOf(_, user_substs) = c_ty.value {
                     // This is a unit-testing mechanism.
                     let span = self.tcx().hir().span(hir_id);
                     // We need to buffer the errors in order to guarantee a consistent
@@ -498,31 +495,49 @@ fn visit_user_provided_tys(&mut self) {
                     err.buffer(&mut errors_buffer);
                 }
             }
-        }
 
-        if !errors_buffer.is_empty() {
-            errors_buffer.sort_by_key(|diag| diag.span.primary_span());
-            for mut diag in errors_buffer {
-                self.tcx().sess.diagnostic().emit_diagnostic(&mut diag);
+            if !errors_buffer.is_empty() {
+                errors_buffer.sort_by_key(|diag| diag.span.primary_span());
+                for mut diag in errors_buffer {
+                    self.tcx().sess.diagnostic().emit_diagnostic(&mut diag);
+                }
             }
         }
+
+        self.typeck_results.user_provided_types_mut().extend(
+            fcx_typeck_results.user_provided_types().items().map(|(local_id, c_ty)| {
+                let hir_id = hir::HirId { owner: common_hir_owner, local_id };
+
+                if cfg!(debug_assertions) && c_ty.needs_infer() {
+                    span_bug!(
+                        hir_id.to_span(self.fcx.tcx),
+                        "writeback: `{:?}` has inference variables",
+                        c_ty
+                    );
+                };
+
+                (hir_id, *c_ty)
+            }),
+        );
     }
 
     fn visit_user_provided_sigs(&mut self) {
         let fcx_typeck_results = self.fcx.typeck_results.borrow();
         assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
 
-        for (&def_id, c_sig) in fcx_typeck_results.user_provided_sigs.iter() {
-            if cfg!(debug_assertions) && c_sig.needs_infer() {
-                span_bug!(
-                    self.fcx.tcx.def_span(def_id),
-                    "writeback: `{:?}` has inference variables",
-                    c_sig
-                );
-            };
-
-            self.typeck_results.user_provided_sigs.insert(def_id, *c_sig);
-        }
+        self.typeck_results.user_provided_sigs.extend(
+            fcx_typeck_results.user_provided_sigs.items().map(|(&def_id, c_sig)| {
+                if cfg!(debug_assertions) && c_sig.needs_infer() {
+                    span_bug!(
+                        self.fcx.tcx.def_span(def_id),
+                        "writeback: `{:?}` has inference variables",
+                        c_sig
+                    );
+                };
+
+                (def_id, *c_sig)
+            }),
+        );
     }
 
     fn visit_generator_interior_types(&mut self) {
@@ -530,6 +545,10 @@ fn visit_generator_interior_types(&mut self) {
         assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
         self.typeck_results.generator_interior_types =
             fcx_typeck_results.generator_interior_types.clone();
+        for (&expr_def_id, predicates) in fcx_typeck_results.generator_interior_predicates.iter() {
+            let predicates = self.resolve(predicates.clone(), &self.fcx.tcx.def_span(expr_def_id));
+            self.typeck_results.generator_interior_predicates.insert(expr_def_id, predicates);
+        }
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -564,7 +583,6 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 opaque_type_key,
                 self.fcx.infcx.tcx,
                 true,
-                decl.origin,
             );
 
             self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
@@ -642,7 +660,9 @@ fn visit_liberated_fn_sigs(&mut self) {
         assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
         let common_hir_owner = fcx_typeck_results.hir_owner;
 
-        for (&local_id, &fn_sig) in fcx_typeck_results.liberated_fn_sigs().iter() {
+        let fcx_liberated_fn_sigs = fcx_typeck_results.liberated_fn_sigs().items_in_stable_order();
+
+        for (local_id, &fn_sig) in fcx_liberated_fn_sigs {
             let hir_id = hir::HirId { owner: common_hir_owner, local_id };
             let fn_sig = self.resolve(fn_sig, &hir_id);
             self.typeck_results.liberated_fn_sigs_mut().insert(hir_id, fn_sig);
@@ -654,7 +674,9 @@ fn visit_fru_field_types(&mut self) {
         assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
         let common_hir_owner = fcx_typeck_results.hir_owner;
 
-        for (&local_id, ftys) in fcx_typeck_results.fru_field_types().iter() {
+        let fcx_fru_field_types = fcx_typeck_results.fru_field_types().items_in_stable_order();
+
+        for (local_id, ftys) in fcx_fru_field_types {
             let hir_id = hir::HirId { owner: common_hir_owner, local_id };
             let ftys = self.resolve(ftys.clone(), &hir_id);
             self.typeck_results.fru_field_types_mut().insert(hir_id, ftys);
index 67b4d6d6959f602c042889c168d0047adf2fbd5b..6703d53f3805cfe2884d2a649d4c033b5149d9e5 100644 (file)
@@ -38,7 +38,7 @@
 use rustc_data_structures::graph::implementation::{Direction, NodeIndex, INCOMING, OUTGOING};
 use rustc_graphviz as dot;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::dep_graph::{
     DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter,
@@ -74,7 +74,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) {
         let (if_this_changed, then_this_would_need) = {
             let mut visitor =
                 IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] };
-            visitor.process_attrs(hir::CRATE_HIR_ID);
+            visitor.process_attrs(CRATE_DEF_ID);
             tcx.hir().visit_all_item_likes_in_crate(&mut visitor);
             (visitor.if_this_changed, visitor.then_this_would_need)
         };
@@ -119,9 +119,9 @@ fn argument(&self, attr: &ast::Attribute) -> Option<Symbol> {
         value
     }
 
-    fn process_attrs(&mut self, hir_id: hir::HirId) {
-        let def_id = self.tcx.hir().local_def_id(hir_id);
+    fn process_attrs(&mut self, def_id: LocalDefId) {
         let def_path_hash = self.tcx.def_path_hash(def_id.to_def_id());
+        let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
         let attrs = self.tcx.hir().attrs(hir_id);
         for attr in attrs {
             if attr.has_name(sym::rustc_if_this_changed) {
@@ -180,22 +180,22 @@ fn nested_visit_map(&mut self) -> Self::Map {
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        self.process_attrs(item.hir_id());
+        self.process_attrs(item.owner_id.def_id);
         intravisit::walk_item(self, item);
     }
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
-        self.process_attrs(trait_item.hir_id());
+        self.process_attrs(trait_item.owner_id.def_id);
         intravisit::walk_trait_item(self, trait_item);
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
-        self.process_attrs(impl_item.hir_id());
+        self.process_attrs(impl_item.owner_id.def_id);
         intravisit::walk_impl_item(self, impl_item);
     }
 
     fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
-        self.process_attrs(s.hir_id);
+        self.process_attrs(s.def_id);
         intravisit::walk_field_def(self, s);
     }
 }
@@ -368,7 +368,7 @@ fn walk_between<'q>(
 ) -> FxHashSet<DepKind> {
     // This is a bit tricky. We want to include a node only if it is:
     // (a) reachable from a source and (b) will reach a target. And we
-    // have to be careful about cycles etc.  Luckily efficiency is not
+    // have to be careful about cycles etc. Luckily efficiency is not
     // a big concern!
 
     #[derive(Copy, Clone, PartialEq)]
index d1d328128bc15a145f7b60835cdfe62f7733beae..ed7b272b13d178087c969aa3bda7f25da0bdec9a 100644 (file)
@@ -1,4 +1,4 @@
-//! Debugging code to test fingerprints computed for query results.  For each node marked with
+//! Debugging code to test fingerprints computed for query results. For each node marked with
 //! `#[rustc_clean]` we will compare the fingerprint from the current and from the previous
 //! compilation session as appropriate:
 //!
index c18a911b2fbcd4db06dfe417f9efbfee8579a4a2..68cdc6d7711d4eb840bb49ea3faef8a6c0f121f5 100644 (file)
@@ -207,7 +207,12 @@ pub fn drain_enumerated<'a, R: RangeBounds<usize>>(
         &'a mut self,
         range: R,
     ) -> impl Iterator<Item = (I, T)> + 'a {
-        self.raw.drain(range).enumerate().map(|(n, t)| (I::new(n), t))
+        let begin = match range.start_bound() {
+            std::ops::Bound::Included(i) => *i,
+            std::ops::Bound::Excluded(i) => i.checked_add(1).unwrap(),
+            std::ops::Bound::Unbounded => 0,
+        };
+        self.raw.drain(range).enumerate().map(move |(n, t)| (I::new(begin + n), t))
     }
 
     #[inline]
index 033a1842edb25c57c95ea20d97c910be67a82c3e..8bf3a160abbb4aaf2f064fef5967b0f3b7b83e8b 100644 (file)
@@ -927,6 +927,8 @@ pub struct ButNeedsToSatisfy {
     #[subdiagnostic]
     pub req_introduces_loc: Option<ReqIntroducedLocations>,
 
+    pub has_param_name: bool,
+    pub param_name: String,
     pub spans_empty: bool,
     pub has_lifetime: bool,
     pub lifetime: String,
index 091635e6c73c0b1c18cbac1a16c83b3bb85b537a..87c6dfad5fa2bd01b79578277f8f8c329af1f567 100644 (file)
@@ -435,6 +435,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
             ty::Closure(..)
             | ty::Generator(..)
             | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..)
             | ty::Bool
             | ty::Char
             | ty::Int(..)
index e59715b706b29c0c4da6afde7ba99fe9b5a3f737..f7e3e4a1cc09ee2583ecbce9e4c0c2269e3c8c5a 100644 (file)
@@ -26,7 +26,7 @@
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::GenericArg;
-use rustc_middle::ty::{self, BoundVar, List};
+use rustc_middle::ty::{self, List};
 use rustc_span::source_map::Span;
 
 pub use rustc_middle::infer::canonical::*;
@@ -87,12 +87,13 @@ fn instantiate_canonical_vars(
         variables: &List<CanonicalVarInfo<'tcx>>,
         universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
     ) -> CanonicalVarValues<'tcx> {
-        let var_values: IndexVec<BoundVar, GenericArg<'tcx>> = variables
-            .iter()
-            .map(|info| self.instantiate_canonical_var(span, info, &universe_map))
-            .collect();
-
-        CanonicalVarValues { var_values }
+        CanonicalVarValues {
+            var_values: self.tcx.mk_substs(
+                variables
+                    .iter()
+                    .map(|info| self.instantiate_canonical_var(span, info, &universe_map)),
+            ),
+        }
     }
 
     /// Given the "info" about a canonical variable, creates a fresh
index 3d49182f0b8172d1edd7bb371b743ef0989e8243..3e8e7734a5a5de61d34fefba70cf674f0be512d7 100644 (file)
@@ -17,7 +17,7 @@
 use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
 use crate::traits::query::{Fallible, NoSolution};
 use crate::traits::{Obligation, ObligationCause, PredicateObligation};
-use crate::traits::{PredicateObligations, TraitEngine};
+use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt};
 use rustc_data_structures::captures::Captures;
 use rustc_index::vec::Idx;
 use rustc_index::vec::IndexVec;
@@ -482,11 +482,8 @@ fn query_response_substitution_guess<R>(
         // given variable in the loop above, use that. Otherwise, use
         // a fresh inference variable.
         let result_subst = CanonicalVarValues {
-            var_values: query_response
-                .variables
-                .iter()
-                .enumerate()
-                .map(|(index, info)| {
+            var_values: self.tcx.mk_substs(query_response.variables.iter().enumerate().map(
+                |(index, info)| {
                     if info.is_existential() {
                         match opt_values[BoundVar::new(index)] {
                             Some(k) => k,
@@ -499,8 +496,8 @@ fn query_response_substitution_guess<R>(
                             universe_map[u.as_usize()]
                         })
                     }
-                })
-                .collect(),
+                },
+            )),
         };
 
         let mut obligations = vec![];
index 389afe22eb7672afe16c801ca97c9b1c940390fe..e77f2d37b7dae8d5c6314c8f22092d28d05b95b1 100644 (file)
@@ -72,16 +72,15 @@ pub(super) fn substitute_value<'tcx, T>(
         value
     } else {
         let delegate = FnMutDelegate {
-            regions: &mut |br: ty::BoundRegion| match var_values.var_values[br.var].unpack() {
+            regions: &mut |br: ty::BoundRegion| match var_values[br.var].unpack() {
                 GenericArgKind::Lifetime(l) => l,
                 r => bug!("{:?} is a region but value is {:?}", br, r),
             },
-            types: &mut |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() {
+            types: &mut |bound_ty: ty::BoundTy| match var_values[bound_ty.var].unpack() {
                 GenericArgKind::Type(ty) => ty,
                 r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
             },
-            consts: &mut |bound_ct: ty::BoundVar, _| match var_values.var_values[bound_ct].unpack()
-            {
+            consts: &mut |bound_ct: ty::BoundVar, _| match var_values[bound_ct].unpack() {
                 GenericArgKind::Const(ct) => ct,
                 c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
             },
index 77e38e47fcfa0b5ee9eb1e0dfd676ac9dae4ecab..a567b6acdbeeb2dc802175bea078a979d6795a7c 100644 (file)
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{
+    self, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
+    TypeVisitable,
+};
 use rustc_middle::ty::{IntType, UintType};
 use rustc_span::{Span, DUMMY_SP};
 
@@ -140,8 +143,6 @@ pub fn super_combine_consts<R>(
         let a = self.shallow_resolve(a);
         let b = self.shallow_resolve(b);
 
-        let a_is_expected = relation.a_is_expected();
-
         match (a.kind(), b.kind()) {
             (
                 ty::ConstKind::Infer(InferConst::Var(a_vid)),
@@ -158,11 +159,11 @@ pub fn super_combine_consts<R>(
             }
 
             (ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
-                return self.unify_const_variable(relation.param_env(), vid, b, a_is_expected);
+                return self.unify_const_variable(vid, b);
             }
 
             (_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
-                return self.unify_const_variable(relation.param_env(), vid, a, !a_is_expected);
+                return self.unify_const_variable(vid, a);
             }
             (ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => {
                 // FIXME(#59490): Need to remove the leak check to accommodate
@@ -223,10 +224,8 @@ pub fn super_combine_consts<R>(
     #[instrument(level = "debug", skip(self))]
     fn unify_const_variable(
         &self,
-        param_env: ty::ParamEnv<'tcx>,
         target_vid: ty::ConstVid<'tcx>,
         ct: ty::Const<'tcx>,
-        vid_is_expected: bool,
     ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         let (for_universe, span) = {
             let mut inner = self.inner.borrow_mut();
@@ -239,8 +238,12 @@ fn unify_const_variable(
                 ConstVariableValue::Unknown { universe } => (universe, var_value.origin.span),
             }
         };
-        let value = ConstInferUnifier { infcx: self, span, param_env, for_universe, target_vid }
-            .relate(ct, ct)?;
+        let value = ct.try_fold_with(&mut ConstInferUnifier {
+            infcx: self,
+            span,
+            for_universe,
+            target_vid,
+        })?;
 
         self.inner.borrow_mut().const_unification_table().union_value(
             target_vid,
@@ -331,7 +334,7 @@ pub fn instantiate(
         debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown());
 
         // Generalize type of `a_ty` appropriately depending on the
-        // direction.  As an example, assume:
+        // direction. As an example, assume:
         //
         // - `a_ty == &'x ?1`, where `'x` is some free region and `?1` is an
         //   inference variable,
@@ -800,8 +803,6 @@ struct ConstInferUnifier<'cx, 'tcx> {
 
     span: Span,
 
-    param_env: ty::ParamEnv<'tcx>,
-
     for_universe: ty::UniverseIndex,
 
     /// The vid of the const variable that is in the process of being
@@ -810,61 +811,15 @@ struct ConstInferUnifier<'cx, 'tcx> {
     target_vid: ty::ConstVid<'tcx>,
 }
 
-// We use `TypeRelation` here to propagate `RelateResult` upwards.
-//
-// Both inputs are expected to be the same.
-impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn intercrate(&self) -> bool {
-        assert!(!self.infcx.intercrate);
-        false
-    }
-
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
-    }
-
-    fn tag(&self) -> &'static str {
-        "ConstInferUnifier"
-    }
-
-    fn a_is_expected(&self) -> bool {
-        true
-    }
-
-    fn mark_ambiguous(&mut self) {
-        bug!()
-    }
-
-    fn relate_with_variance<T: Relate<'tcx>>(
-        &mut self,
-        _variance: ty::Variance,
-        _info: ty::VarianceDiagInfo<'tcx>,
-        a: T,
-        b: T,
-    ) -> RelateResult<'tcx, T> {
-        // We don't care about variance here.
-        self.relate(a, b)
-    }
+impl<'tcx> FallibleTypeFolder<'tcx> for ConstInferUnifier<'_, 'tcx> {
+    type Error = TypeError<'tcx>;
 
-    fn binders<T>(
-        &mut self,
-        a: ty::Binder<'tcx, T>,
-        b: ty::Binder<'tcx, T>,
-    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
-    where
-        T: Relate<'tcx>,
-    {
-        Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
+    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
     }
 
     #[instrument(level = "debug", skip(self), ret)]
-    fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        debug_assert_eq!(t, _t);
-
+    fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, TypeError<'tcx>> {
         match t.kind() {
             &ty::Infer(ty::TyVar(vid)) => {
                 let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid);
@@ -872,7 +827,7 @@ fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                 match probe {
                     TypeVariableValue::Known { value: u } => {
                         debug!("ConstOccursChecker: known value {:?}", u);
-                        self.tys(u, u)
+                        u.try_fold_with(self)
                     }
                     TypeVariableValue::Unknown { universe } => {
                         if self.for_universe.can_name(universe) {
@@ -892,16 +847,15 @@ fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                 }
             }
             ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => Ok(t),
-            _ => relate::super_relate_tys(self, t, t),
+            _ => t.try_super_fold_with(self),
         }
     }
 
-    fn regions(
+    #[instrument(level = "debug", skip(self), ret)]
+    fn try_fold_region(
         &mut self,
         r: ty::Region<'tcx>,
-        _r: ty::Region<'tcx>,
-    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        debug_assert_eq!(r, _r);
+    ) -> Result<ty::Region<'tcx>, TypeError<'tcx>> {
         debug!("ConstInferUnifier: r={:?}", r);
 
         match *r {
@@ -930,14 +884,8 @@ fn regions(
         }
     }
 
-    #[instrument(level = "debug", skip(self))]
-    fn consts(
-        &mut self,
-        c: ty::Const<'tcx>,
-        _c: ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
-        debug_assert_eq!(c, _c);
-
+    #[instrument(level = "debug", skip(self), ret)]
+    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, TypeError<'tcx>> {
         match c.kind() {
             ty::ConstKind::Infer(InferConst::Var(vid)) => {
                 // Check if the current unification would end up
@@ -958,7 +906,7 @@ fn consts(
                 let var_value =
                     self.infcx.inner.borrow_mut().const_unification_table().probe_value(vid);
                 match var_value.val {
-                    ConstVariableValue::Known { value: u } => self.consts(u, u),
+                    ConstVariableValue::Known { value: u } => u.try_fold_with(self),
                     ConstVariableValue::Unknown { universe } => {
                         if self.for_universe.can_name(universe) {
                             Ok(c)
@@ -977,17 +925,7 @@ fn consts(
                     }
                 }
             }
-            ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
-                let substs = self.relate_with_variance(
-                    ty::Variance::Invariant,
-                    ty::VarianceDiagInfo::default(),
-                    substs,
-                    substs,
-                )?;
-
-                Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty()))
-            }
-            _ => relate::super_relate_consts(self, c, c),
+            _ => c.try_super_fold_with(self),
         }
     }
 }
index 533a3c768eb1693144f6673fcb5175bb2ab68b95..b11db8396c9203e9e840c599590c8da6a2885c6e 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;
@@ -1344,8 +1345,8 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
             }
 
             (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);
+                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
+                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
                 let mut values = self.cmp_fn_sig(&sig1, &sig2);
                 let path1 = format!(" {{{}}}", self.tcx.def_path_str_with_substs(*did1, substs1));
                 let path2 = format!(" {{{}}}", self.tcx.def_path_str_with_substs(*did2, substs2));
@@ -1356,7 +1357,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
             }
 
             (ty::FnDef(did1, substs1), ty::FnPtr(sig2)) => {
-                let sig1 = self.tcx.bound_fn_sig(*did1).subst(self.tcx, substs1);
+                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
                 let mut values = self.cmp_fn_sig(&sig1, sig2);
                 values.0.push_highlighted(format!(
                     " {{{}}}",
@@ -1366,7 +1367,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
             }
 
             (ty::FnPtr(sig1), ty::FnDef(did2, substs2)) => {
-                let sig2 = self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2);
+                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
                 let mut values = self.cmp_fn_sig(sig1, &sig2);
                 values.1.push_normal(format!(
                     " {{{}}}",
@@ -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()
@@ -1923,6 +1918,22 @@ fn escape_literal(s: &str) -> String {
                         (ty::Tuple(fields), _) => {
                             self.emit_tuple_wrap_err(&mut err, span, found, fields)
                         }
+                        // If a byte was expected and the found expression is a char literal
+                        // containing a single ASCII character, perhaps the user meant to write `b'c'` to
+                        // specify a byte literal
+                        (ty::Uint(ty::UintTy::U8), ty::Char) => {
+                            if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
+                                && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
+                                && code.chars().next().map_or(false, |c| c.is_ascii())
+                            {
+                                err.span_suggestion(
+                                    span,
+                                    "if you meant to write a byte literal, prefix with `b`",
+                                    format!("b'{}'", escape_literal(code)),
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                        }
                         // If a character was expected and the found expression is a string literal
                         // containing a single character, perhaps the user meant to write `'c'` to
                         // specify a character literal (issue #92479)
@@ -2256,10 +2267,10 @@ pub fn construct_generic_bound_failure(
 
         let labeled_user_string = match bound_kind {
             GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
-            GenericKind::Projection(ref p) => format!("the associated type `{}`", p),
-            GenericKind::Opaque(def_id, substs) => {
-                format!("the opaque type `{}`", self.tcx.def_path_str_with_substs(def_id, substs))
-            }
+            GenericKind::Alias(ref p) => match p.kind(self.tcx) {
+                ty::AliasKind::Projection => format!("the associated type `{}`", p),
+                ty::AliasKind::Opaque => format!("the opaque type `{}`", p),
+            },
         };
 
         if let Some(SubregionOrigin::CompareImplItemObligation {
@@ -2569,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()
     }
index 202f39521e967d7283fbfe8b747ccb94788878ed..99431567edac413f4aef86a04e49516ddf932599 100644 (file)
@@ -370,7 +370,7 @@ fn explain_actual_impl_that_was_found(
         //   in the types are about to print
         // - Meanwhile, the `maybe_highlighting_region` calls set up
         //   highlights so that, if they do appear, we will replace
-        //   them `'0` and whatever.  (This replacement takes place
+        //   them `'0` and whatever. (This replacement takes place
         //   inside the closure given to `maybe_highlighting_region`.)
         //
         // There is some duplication between the calls -- i.e., the
index fb0f09198ccc185330064cb2b7df525d1048f26c..6a463583dfb0ff42573d3cbf0c308ef67fe434a1 100644 (file)
@@ -98,6 +98,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
         let sp = var_origin.span();
         let return_sp = sub_origin.span();
         let param = self.find_param_with_region(*sup_r, *sub_r)?;
+        let simple_ident = param.param.pat.simple_ident();
         let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
 
         let (mention_influencer, influencer_point) =
@@ -187,7 +188,9 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
             req_introduces_loc: subdiag,
 
             has_lifetime: sup_r.has_name(),
-            lifetime: sup_r.to_string(),
+            lifetime: lifetime_name.clone(),
+            has_param_name: simple_ident.is_some(),
+            param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(),
             spans_empty,
             bound,
         };
@@ -543,7 +546,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if let Some(def_id) = preds.principal_def_id() {
                     self.0.insert(def_id);
                 }
-                ControlFlow::CONTINUE
+                ControlFlow::Continue(())
             }
             _ => t.super_visit_with(self),
         }
index fd26d7d29c5ee6ba1f13554126a8255e54323fd5..4c0f457b46a7c76cbee3ebc7e4743e90272b4d08 100644 (file)
@@ -65,7 +65,7 @@ pub fn find_param_with_region<'tcx>(
 
     let owner_id = hir.body_owner(body_id);
     let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
-    let poly_fn_sig = tcx.fn_sig(id);
+    let poly_fn_sig = tcx.fn_sig(id).subst_identity();
 
     let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig);
     let body = hir.body(body_id);
index 7504ed094a3d4160715436ac3981b6f1729e45e3..b18cbd404d47f8c03895ef5db759d18f4f722077 100644 (file)
@@ -320,6 +320,7 @@ pub fn suggest_copy_trait_method_bounds(
             .impl_trait_ref(impl_def_id)
             else { return; };
         let trait_substs = trait_ref
+            .subst_identity()
             // Replace the explicit self type with `Self` for better suggestion rendering
             .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
             .substs;
@@ -329,9 +330,8 @@ pub fn suggest_copy_trait_method_bounds(
 
         let Ok(trait_predicates) = self
             .tcx
-            .bound_explicit_predicates_of(trait_item_def_id)
-            .map_bound(|p| p.predicates)
-            .subst_iter_copied(self.tcx, trait_item_substs)
+            .explicit_predicates_of(trait_item_def_id)
+            .instantiate_own(self.tcx, trait_item_substs)
             .map(|(pred, _)| {
                 if pred.is_suggestable(self.tcx, false) {
                     Ok(pred.to_string())
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..34e8edd
--- /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).subst_identity();
+                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..23063e80b05ff117091c95c35bdfa728f8de1584 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.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.fn_sig(*did1).subst(self.tcx, substs1));
+                let found_sig =
+                    &(self.normalize_fn_sig)(self.tcx.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.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 8f53b1ccdf45829c758721072cf55d1063f730ff..83d71edc2abd927a640819ce5a71e28b4b8409a4 100644 (file)
@@ -209,6 +209,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
             | ty::Foreign(..)
             | ty::Param(..)
             | ty::Closure(..)
+            | ty::GeneratorWitnessMIR(..)
             | ty::GeneratorWitness(..) => t.super_fold_with(self),
 
             ty::Placeholder(..) | ty::Bound(..) => bug!("unexpected type {:?}", t),
index 21b68ce998997a6826645c6ad0036f2af522bb7d..b92b162a9786a652dd51a0e8085251718e8f5a4f 100644 (file)
@@ -79,7 +79,8 @@ fn regions(
         debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
 
         let origin = Subtype(Box::new(self.fields.trace.clone()));
-        Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions(
+        // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8
+        Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions(
             self.tcx(),
             origin,
             a,
index 0ebc6d55bcba952678c86e6ff3c1dba91d8a11bd..4dbb4b4d7b4da8b681d38180acc87270092f1fd6 100644 (file)
@@ -78,7 +78,7 @@ pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
         //
         // Example: if the LHS is a type variable, and RHS is
         // `Box<i32>`, then we current compare `v` to the RHS first,
-        // which will instantiate `v` with `Box<i32>`.  Then when `v`
+        // which will instantiate `v` with `Box<i32>`. Then when `v`
         // is compared to the LHS, we instantiate LHS with `Box<i32>`.
         // But if we did in reverse order, we would create a `v <:
         // LHS` (or vice versa) constraint and then instantiate
index 897545046c33f3bfd2b6886e974ab1f1673409ea..ce8aec8044bae63422a1fba1131dcd8b6aaaf746 100644 (file)
@@ -52,7 +52,7 @@ pub struct LexicalRegionResolutions<'tcx> {
 
 #[derive(Copy, Clone, Debug)]
 pub(crate) enum VarValue<'tcx> {
-    /// Empty lifetime is for data that is never accessed.  We tag the
+    /// Empty lifetime is for data that is never accessed. We tag the
     /// empty lifetime with a universe -- the idea is that we don't
     /// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable.
     /// Therefore, the `'empty` in a universe `U` is less than all
@@ -251,7 +251,7 @@ fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
                     VarValue::Empty(a_universe) => {
                         let b_data = var_values.value_mut(b_vid);
 
-                        let changed = (|| match *b_data {
+                        let changed = match *b_data {
                             VarValue::Empty(b_universe) => {
                                 // Empty regions are ordered according to the universe
                                 // they are associated with.
@@ -280,20 +280,20 @@ fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
                                 };
 
                                 if lub == cur_region {
-                                    return false;
+                                    false
+                                } else {
+                                    debug!(
+                                        "Expanding value of {:?} from {:?} to {:?}",
+                                        b_vid, cur_region, lub
+                                    );
+
+                                    *b_data = VarValue::Value(lub);
+                                    true
                                 }
-
-                                debug!(
-                                    "Expanding value of {:?} from {:?} to {:?}",
-                                    b_vid, cur_region, lub
-                                );
-
-                                *b_data = VarValue::Value(lub);
-                                true
                             }
 
                             VarValue::ErrorValue => false,
-                        })();
+                        };
 
                         if changed {
                             changes.push(b_vid);
@@ -510,7 +510,7 @@ fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
         }
 
         // If both `a` and `b` are free, consult the declared
-        // relationships.  Note that this can be more precise than the
+        // relationships. Note that this can be more precise than the
         // `lub` relationship defined below, since sometimes the "lub"
         // is actually the `postdom_upper_bound` (see
         // `TransitiveRelation` for more details).
@@ -665,7 +665,7 @@ fn collect_var_errors(
         // conflicting regions to report to the user. As we walk, we
         // trip the flags from false to true, and if we find that
         // we've already reported an error involving any particular
-        // node we just stop and don't report the current error.  The
+        // node we just stop and don't report the current error. The
         // idea is to report errors that derive from independent
         // regions of the graph, but not those that derive from
         // overlapping locations.
index c07ac1d3ace92a4375b03797534a725c7b26911e..f6e0554fd1f951634bfa9b78a7123b3338b286d9 100644 (file)
@@ -79,7 +79,8 @@ fn regions(
         debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
 
         let origin = Subtype(Box::new(self.fields.trace.clone()));
-        Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions(
+        // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8
+        Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions(
             self.tcx(),
             origin,
             a,
index 4acd0d0edfec774546b1a73bda0ae049d8fe720e..f0e42c1fce49c3ea685f6301b22f1d09e702e774 100644 (file)
@@ -1105,7 +1105,7 @@ pub fn next_region_var_in_universe(
         self.tcx.mk_region(ty::ReVar(region_var))
     }
 
-    /// Return the universe that the region `r` was created in.  For
+    /// Return the universe that the region `r` was created in. For
     /// most regions (e.g., `'static`, named regions from the user,
     /// etc) this is the root universe U0. For inference variables or
     /// placeholders, however, it will return the universe which they
@@ -1361,7 +1361,7 @@ pub fn probe_ty_var(&self, vid: TyVid) -> Result<Ty<'tcx>, ty::UniverseIndex> {
     }
 
     /// Resolve any type variables found in `value` -- but only one
-    /// level.  So, if the variable `?X` is bound to some type
+    /// level. So, if the variable `?X` is bound to some type
     /// `Foo<?Y>`, then this would return `Foo<?Y>` (but `?Y` may
     /// itself be bound to a type).
     ///
@@ -1720,7 +1720,7 @@ pub fn resolve_regions_and_report_errors(
         if let None = self.tainted_by_errors() {
             // As a heuristic, just skip reporting region errors
             // altogether if other errors have been reported while
-            // this infcx was in use.  This is totally hokey but
+            // this infcx was in use. This is totally hokey but
             // otherwise we have a hard time separating legit region
             // errors from silly ones.
             self.report_region_errors(generic_param_scope, &errors);
index 1f9d86a78d6e50912f7cc3dba6e0b006391a33aa..f83219b8ee2a0e0ad1e80f374f6d12dd4574aa5c 100644 (file)
@@ -439,7 +439,7 @@ trait VidValuePair<'tcx>: Debug {
     fn value_ty(&self) -> Ty<'tcx>;
 
     /// Extract the scopes that apply to whichever side of the tuple
-    /// the vid was found on.  See the comment where this is called
+    /// the vid was found on. See the comment where this is called
     /// for more details on why we want them.
     fn vid_scopes<'r, D: TypeRelatingDelegate<'tcx>>(
         &self,
@@ -663,13 +663,13 @@ fn regions(
         debug!(?v_b);
 
         if self.ambient_covariance() {
-            // Covariance: a <= b. Hence, `b: a`.
-            self.push_outlives(v_b, v_a, self.ambient_variance_info);
+            // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
+            self.push_outlives(v_a, v_b, self.ambient_variance_info);
         }
 
         if self.ambient_contravariance() {
-            // Contravariant: b <= a. Hence, `a: b`.
-            self.push_outlives(v_a, v_b, self.ambient_variance_info);
+            // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
+            self.push_outlives(v_b, v_a, self.ambient_variance_info);
         }
 
         Ok(a)
@@ -831,7 +831,7 @@ fn const_equate_obligation(&mut self, _a: ty::Const<'tcx>, _b: ty::Const<'tcx>)
 /// (these are not explicitly present in the ty representation right
 /// now). This visitor handles that: it descends the type, tracking
 /// binder depth, and finds late-bound regions targeting the
-/// `for<..`>.  For each of those, it creates an entry in
+/// `for<..`>. For each of those, it creates an entry in
 /// `bound_region_scope`.
 struct ScopeInstantiator<'me, 'tcx> {
     next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
@@ -849,7 +849,7 @@ fn visit_binder<T: TypeVisitable<'tcx>>(
         t.super_visit_with(self);
         self.target_index.shift_out(1);
 
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -863,7 +863,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             _ => {}
         }
 
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 }
 
index 749e960bfd03090876186167b6b6247b5eb44efc..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> {
@@ -112,7 +112,7 @@ pub fn handle_opaque_type(
                     DefiningAnchor::Bind(_) => {
                         // Check that this is `impl Trait` type is
                         // declared by `parent_def_id` -- i.e., one whose
-                        // value we are inferring.  At present, this is
+                        // value we are inferring. At present, this is
                         // always true during the first phase of
                         // type-check, but not always true later on during
                         // NLL. Once we support named opaque types more fully,
@@ -380,7 +380,7 @@ pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<Opaqu
         };
         let item_kind = &self.tcx.hir().expect_item(def_id).kind;
 
-        let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, ..  }) = item_kind else {
+        let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {
             span_bug!(
                 span,
                 "weird opaque type: {:#?}, {:#?}",
@@ -440,16 +440,16 @@ fn visit_binder<T: TypeVisitable<'tcx>>(
         t: &ty::Binder<'tcx, T>,
     ) -> ControlFlow<Self::BreakTy> {
         t.super_visit_with(self);
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         match *r {
             // ignore bound regions, keep visiting
-            ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
+            ty::ReLateBound(_, _) => ControlFlow::Continue(()),
             _ => {
                 (self.op)(r);
-                ControlFlow::CONTINUE
+                ControlFlow::Continue(())
             }
         }
     }
@@ -457,7 +457,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         // We're only interested in types involving regions
         if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
-            return ControlFlow::CONTINUE;
+            return ControlFlow::Continue(());
         }
 
         match ty.kind() {
@@ -479,7 +479,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
 
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, ref substs, .. }) => {
-                // Skip lifetime paramters that are not captures.
+                // Skip lifetime parameters that are not captures.
                 let variances = self.tcx.variances_of(*def_id);
 
                 for (v, s) in std::iter::zip(variances, substs.iter()) {
@@ -492,7 +492,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             ty::Alias(ty::Projection, proj)
                 if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder =>
             {
-                // Skip lifetime paramters that are not captures.
+                // Skip lifetime parameters that are not captures.
                 let variances = self.tcx.variances_of(proj.def_id);
 
                 for (v, s) in std::iter::zip(variances, proj.substs.iter()) {
@@ -507,7 +507,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
         }
 
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 }
 
index aa2b5d067d266d8742c322ea147ffe5bc4905442..e3d9566917125546c49c5383572fe27625861895 100644 (file)
@@ -3,9 +3,8 @@
 // RFC for reference.
 
 use rustc_data_structures::sso::SsoHashSet;
-use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
 use smallvec::{smallvec, SmallVec};
 
 #[derive(Debug)]
@@ -23,7 +22,7 @@ pub enum Component<'tcx> {
     // is not in a position to judge which is the best technique, so
     // we just product the projection as a component and leave it to
     // the consumer to decide (but see `EscapingProjection` below).
-    Projection(ty::AliasTy<'tcx>),
+    Alias(ty::AliasTy<'tcx>),
 
     // In the case where a projection has escaping regions -- meaning
     // regions bound within the type itself -- we always use
@@ -45,9 +44,7 @@ pub enum Component<'tcx> {
     // projection, so that implied bounds code can avoid relying on
     // them. This gives us room to improve the regionck reasoning in
     // the future without breaking backwards compat.
-    EscapingProjection(Vec<Component<'tcx>>),
-
-    Opaque(DefId, SubstsRef<'tcx>),
+    EscapingAlias(Vec<Component<'tcx>>),
 }
 
 /// Push onto `out` all the things that must outlive `'a` for the condition
@@ -115,7 +112,7 @@ fn compute_components<'tcx>(
             }
 
             // All regions are bound inside a witness
-            ty::GeneratorWitness(..) => (),
+            ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => (),
 
             // OutlivesTypeParameterEnv -- the actual checking that `X:'a`
             // is implied by the environment is done in regionck.
@@ -123,17 +120,6 @@ fn compute_components<'tcx>(
                 out.push(Component::Param(p));
             }
 
-            // Ignore lifetimes found in opaque types. Opaque types can
-            // have lifetimes in their substs which their hidden type doesn't
-            // actually use. If we inferred that an opaque type is outlived by
-            // its parameter lifetimes, then we could prove that any lifetime
-            // outlives any other lifetime, which is unsound.
-            // See https://github.com/rust-lang/rust/issues/84305 for
-            // more details.
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
-                out.push(Component::Opaque(def_id, substs));
-            },
-
             // For projections, we prefer to generate an obligation like
             // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
             // regionck more ways to prove that it holds. However,
@@ -142,23 +128,23 @@ fn compute_components<'tcx>(
             // trait-ref. Therefore, if we see any higher-ranked regions,
             // we simply fallback to the most restrictive rule, which
             // requires that `Pi: 'a` for all `i`.
-            ty::Alias(ty::Projection, ref data) => {
-                if !data.has_escaping_bound_vars() {
+            ty::Alias(_, alias_ty) => {
+                if !alias_ty.has_escaping_bound_vars() {
                     // best case: no escaping regions, so push the
                     // projection and skip the subtree (thus generating no
                     // constraints for Pi). This defers the choice between
                     // the rules OutlivesProjectionEnv,
                     // OutlivesProjectionTraitDef, and
                     // OutlivesProjectionComponents to regionck.
-                    out.push(Component::Projection(*data));
+                    out.push(Component::Alias(alias_ty));
                 } else {
                     // fallback case: hard code
-                    // OutlivesProjectionComponents.  Continue walking
+                    // OutlivesProjectionComponents. Continue walking
                     // through and constrain Pi.
                     let mut subcomponents = smallvec![];
                     let mut subvisited = SsoHashSet::new();
                     compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited);
-                    out.push(Component::EscapingProjection(subcomponents.into_iter().collect()));
+                    out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
                 }
             }
 
@@ -195,7 +181,7 @@ fn compute_components<'tcx>(
             ty::Error(_) => {
                 // (*) Function pointers and trait objects are both binders.
                 // In the RFC, this means we would add the bound regions to
-                // the "bound regions list".  In our representation, no such
+                // the "bound regions list". In our representation, no such
                 // list is maintained explicitly, because bound regions
                 // themselves can be readily identified.
                 compute_components_recursive(tcx, ty.into(), out, visited);
index 33543135ddb0ef68a3f3a92369ca3b629a6d948c..24e3c34dd94fc40d28b22d2ea7675f62b7618144 100644 (file)
@@ -138,13 +138,9 @@ fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'tcx>>, outlives_b
                     self.region_bound_pairs
                         .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
                 }
-                OutlivesBound::RegionSubProjection(r_a, projection_b) => {
+                OutlivesBound::RegionSubAlias(r_a, alias_b) => {
                     self.region_bound_pairs
-                        .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
-                }
-                OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
-                    self.region_bound_pairs
-                        .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
+                        .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
                 }
                 OutlivesBound::RegionSubRegion(r_a, r_b) => {
                     if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
index a85e6a19b11b65b99fdc279a195f5822cd3a4220..0194549a8868d3c5c3506a7ddd839715fca57bfe 100644 (file)
@@ -67,7 +67,6 @@
 };
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::undo_log::UndoLogs;
-use rustc_hir::def_id::DefId;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
@@ -266,13 +265,8 @@ fn components_must_outlive(
                 Component::Param(param_ty) => {
                     self.param_ty_must_outlive(origin, region, *param_ty);
                 }
-                Component::Opaque(def_id, substs) => {
-                    self.opaque_must_outlive(*def_id, substs, origin, region)
-                }
-                Component::Projection(projection_ty) => {
-                    self.projection_must_outlive(origin, region, *projection_ty);
-                }
-                Component::EscapingProjection(subcomponents) => {
+                Component::Alias(alias_ty) => self.alias_ty_must_outlive(origin, region, *alias_ty),
+                Component::EscapingAlias(subcomponents) => {
                     self.components_must_outlive(origin, &subcomponents, region, category);
                 }
                 Component::UnresolvedInferenceVariable(v) => {
@@ -288,80 +282,26 @@ fn components_must_outlive(
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn param_ty_must_outlive(
         &mut self,
         origin: infer::SubregionOrigin<'tcx>,
         region: ty::Region<'tcx>,
         param_ty: ty::ParamTy,
     ) {
-        debug!(
-            "param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})",
-            region, param_ty, origin
-        );
-
-        let generic = GenericKind::Param(param_ty);
         let verify_bound = self.verify_bound.param_bound(param_ty);
-        self.delegate.push_verify(origin, generic, region, verify_bound);
-    }
-
-    #[instrument(level = "debug", skip(self))]
-    fn opaque_must_outlive(
-        &mut self,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
-        origin: infer::SubregionOrigin<'tcx>,
-        region: ty::Region<'tcx>,
-    ) {
-        self.generic_must_outlive(
-            origin,
-            region,
-            GenericKind::Opaque(def_id, substs),
-            def_id,
-            substs,
-            true,
-            |ty| match *ty.kind() {
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => (def_id, substs),
-                _ => bug!("expected only projection types from env, not {:?}", ty),
-            },
-        );
+        self.delegate.push_verify(origin, GenericKind::Param(param_ty), region, verify_bound);
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn projection_must_outlive(
+    fn alias_ty_must_outlive(
         &mut self,
         origin: infer::SubregionOrigin<'tcx>,
         region: ty::Region<'tcx>,
-        projection_ty: ty::AliasTy<'tcx>,
-    ) {
-        self.generic_must_outlive(
-            origin,
-            region,
-            GenericKind::Projection(projection_ty),
-            projection_ty.def_id,
-            projection_ty.substs,
-            false,
-            |ty| match ty.kind() {
-                ty::Alias(ty::Projection, projection_ty) => {
-                    (projection_ty.def_id, projection_ty.substs)
-                }
-                _ => bug!("expected only projection types from env, not {:?}", ty),
-            },
-        );
-    }
-
-    #[instrument(level = "debug", skip(self, filter))]
-    fn generic_must_outlive(
-        &mut self,
-        origin: infer::SubregionOrigin<'tcx>,
-        region: ty::Region<'tcx>,
-        generic: GenericKind<'tcx>,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
-        is_opaque: bool,
-        filter: impl Fn(Ty<'tcx>) -> (DefId, SubstsRef<'tcx>),
+        alias_ty: ty::AliasTy<'tcx>,
     ) {
         // An optimization for a common case with opaque types.
-        if substs.is_empty() {
+        if alias_ty.substs.is_empty() {
             return;
         }
 
@@ -371,7 +311,7 @@ fn generic_must_outlive(
         // particular). :) First off, we have to choose between using the
         // OutlivesProjectionEnv, OutlivesProjectionTraitDef, and
         // OutlivesProjectionComponent rules, any one of which is
-        // sufficient.  If there are no inference variables involved, it's
+        // sufficient. If there are no inference variables involved, it's
         // not hard to pick the right rule, but if there are, we're in a
         // bit of a catch 22: if we picked which rule we were going to
         // use, we could add constraints to the region inference graph
@@ -383,14 +323,14 @@ fn generic_must_outlive(
         // These are guaranteed to apply, no matter the inference
         // results.
         let trait_bounds: Vec<_> =
-            self.verify_bound.declared_region_bounds(def_id, substs).collect();
+            self.verify_bound.declared_bounds_from_definition(alias_ty).collect();
 
         debug!(?trait_bounds);
 
         // Compute the bounds we can derive from the environment. This
         // is an "approximate" match -- in some cases, these bounds
         // may not apply.
-        let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(generic);
+        let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(alias_ty);
         debug!(?approx_env_bounds);
 
         // Remove outlives bounds that we get from the environment but
@@ -405,8 +345,8 @@ fn generic_must_outlive(
             // If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
             // will be invoked with `['b => ^1]` and so we will get `^1` returned.
             let bound = bound_outlives.skip_binder();
-            let (def_id, substs) = filter(bound.0);
-            self.verify_bound.declared_region_bounds(def_id, substs).all(|r| r != bound.1)
+            let ty::Alias(_, alias_ty) = bound.0.kind() else { bug!("expected AliasTy") };
+            self.verify_bound.declared_bounds_from_definition(*alias_ty).all(|r| r != bound.1)
         });
 
         // If declared bounds list is empty, the only applicable rule is
@@ -423,12 +363,12 @@ fn generic_must_outlive(
         // the problem is to add `T: 'r`, which isn't true. So, if there are no
         // inference variables, we use a verify constraint instead of adding
         // edges, which winds up enforcing the same condition.
-        let needs_infer = substs.needs_infer();
-        if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) {
+        if approx_env_bounds.is_empty()
+            && trait_bounds.is_empty()
+            && (alias_ty.needs_infer() || alias_ty.kind(self.tcx) == ty::Opaque)
+        {
             debug!("no declared bounds");
-
-            self.substs_must_outlive(substs, origin, region);
-
+            self.substs_must_outlive(alias_ty.substs, origin, region);
             return;
         }
 
@@ -469,14 +409,9 @@ fn generic_must_outlive(
         // projection outlive; in some cases, this may add insufficient
         // edges into the inference graph, leading to inference failures
         // even though a satisfactory solution exists.
-        let verify_bound = self.verify_bound.projection_opaque_bounds(
-            generic,
-            def_id,
-            substs,
-            &mut Default::default(),
-        );
-        debug!("projection_must_outlive: pushing {:?}", verify_bound);
-        self.delegate.push_verify(origin, generic, region, verify_bound);
+        let verify_bound = self.verify_bound.alias_bound(alias_ty, &mut Default::default());
+        debug!("alias_must_outlive: pushing {:?}", verify_bound);
+        self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound);
     }
 
     fn substs_must_outlive(
index 40bbec8ddd091da396b17dcb866004b4b10cab20..94de9bc2d02283be28c98c6c576ff4f5c1499027 100644 (file)
@@ -1,11 +1,10 @@
 use crate::infer::outlives::components::{compute_components_recursive, Component};
 use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::region_constraints::VerifyIfEq;
-use crate::infer::{GenericKind, VerifyBound};
+use crate::infer::VerifyBound;
 use rustc_data_structures::sso::SsoHashSet;
-use rustc_hir::def_id::DefId;
 use rustc_middle::ty::GenericArg;
-use rustc_middle::ty::{self, OutlivesPredicate, SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt};
 
 use smallvec::smallvec;
 
@@ -94,29 +93,26 @@ pub fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
     /// this list.
     pub fn approx_declared_bounds_from_env(
         &self,
-        generic: GenericKind<'tcx>,
+        alias_ty: ty::AliasTy<'tcx>,
     ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
-        let projection_ty = generic.to_ty(self.tcx);
-        let erased_projection_ty = self.tcx.erase_regions(projection_ty);
-        self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty)
+        let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx));
+        self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty)
     }
 
     #[instrument(level = "debug", skip(self, visited))]
-    pub fn projection_opaque_bounds(
+    pub fn alias_bound(
         &self,
-        generic: GenericKind<'tcx>,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
+        alias_ty: ty::AliasTy<'tcx>,
         visited: &mut SsoHashSet<GenericArg<'tcx>>,
     ) -> VerifyBound<'tcx> {
-        let generic_ty = generic.to_ty(self.tcx);
+        let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
 
         // Search the env for where clauses like `P: 'a`.
-        let projection_opaque_bounds = self
-            .approx_declared_bounds_from_env(generic)
+        let env_bounds = self
+            .approx_declared_bounds_from_env(alias_ty)
             .into_iter()
             .map(|binder| {
-                if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == generic_ty {
+                if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == alias_ty_as_ty {
                     // Micro-optimize if this is an exact match (this
                     // occurs often when there are no region variables
                     // involved).
@@ -126,19 +122,19 @@ pub fn projection_opaque_bounds(
                     VerifyBound::IfEq(verify_if_eq_b)
                 }
             });
-        // Extend with bounds that we can find from the trait.
-        let trait_bounds =
-            self.declared_region_bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r));
+
+        // Extend with bounds that we can find from the definition.
+        let definition_bounds =
+            self.declared_bounds_from_definition(alias_ty).map(|r| VerifyBound::OutlivedBy(r));
 
         // see the extensive comment in projection_must_outlive
         let recursive_bound = {
             let mut components = smallvec![];
-            compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited);
+            compute_components_recursive(self.tcx, alias_ty_as_ty.into(), &mut components, visited);
             self.bound_from_components(&components, visited)
         };
 
-        VerifyBound::AnyBound(projection_opaque_bounds.chain(trait_bounds).collect())
-            .or(recursive_bound)
+        VerifyBound::AnyBound(env_bounds.chain(definition_bounds).collect()).or(recursive_bound)
     }
 
     fn bound_from_components(
@@ -149,10 +145,8 @@ fn bound_from_components(
         let mut bounds = components
             .iter()
             .map(|component| self.bound_from_single_component(component, visited))
-            .filter(|bound| {
-                // Remove bounds that must hold, since they are not interesting.
-                !bound.must_hold()
-            });
+            // Remove bounds that must hold, since they are not interesting.
+            .filter(|bound| !bound.must_hold());
 
         match (bounds.next(), bounds.next()) {
             (Some(first), None) => first,
@@ -170,19 +164,8 @@ fn bound_from_single_component(
         match *component {
             Component::Region(lt) => VerifyBound::OutlivedBy(lt),
             Component::Param(param_ty) => self.param_bound(param_ty),
-            Component::Opaque(did, substs) => self.projection_opaque_bounds(
-                GenericKind::Opaque(did, substs),
-                did,
-                substs,
-                visited,
-            ),
-            Component::Projection(projection_ty) => self.projection_opaque_bounds(
-                GenericKind::Projection(projection_ty),
-                projection_ty.def_id,
-                projection_ty.substs,
-                visited,
-            ),
-            Component::EscapingProjection(ref components) => {
+            Component::Alias(alias_ty) => self.alias_bound(alias_ty, visited),
+            Component::EscapingAlias(ref components) => {
                 self.bound_from_components(components, visited)
             }
             Component::UnresolvedInferenceVariable(v) => {
@@ -298,16 +281,15 @@ fn declared_generic_bounds_from_env_for_erased_ty(
     ///
     /// This is for simplicity, and because we are not really smart
     /// enough to cope with such bounds anywhere.
-    pub fn declared_region_bounds(
+    pub fn declared_bounds_from_definition(
         &self,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
+        alias_ty: ty::AliasTy<'tcx>,
     ) -> impl Iterator<Item = ty::Region<'tcx>> {
         let tcx = self.tcx;
-        let bounds = tcx.bound_item_bounds(def_id);
+        let bounds = tcx.item_bounds(alias_ty.def_id);
         trace!("{:#?}", bounds.0);
         bounds
-            .subst_iter(tcx, substs)
+            .subst_iter(tcx, alias_ty.substs)
             .filter_map(|p| p.to_opt_type_outlives())
             .filter_map(|p| p.no_bound_vars())
             .map(|OutlivesPredicate(_, r)| r)
index 9a427ceacd0a7c63737805a2cb370adfa6788d7c..0428481b7ff0282fff2ba59b311733e25c1fbd39 100644 (file)
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::UndoLogs;
 use rustc_data_structures::unify as ut;
-use rustc_hir::def_id::DefId;
 use rustc_index::vec::IndexVec;
 use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
-use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ReStatic;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ReLateBound, ReVar};
@@ -169,8 +167,7 @@ pub struct Verify<'tcx> {
 #[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
 pub enum GenericKind<'tcx> {
     Param(ty::ParamTy),
-    Projection(ty::AliasTy<'tcx>),
-    Opaque(DefId, SubstsRef<'tcx>),
+    Alias(ty::AliasTy<'tcx>),
 }
 
 /// Describes the things that some `GenericKind` value `G` is known to
@@ -749,10 +746,7 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             GenericKind::Param(ref p) => write!(f, "{:?}", p),
-            GenericKind::Projection(ref p) => write!(f, "{:?}", p),
-            GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
-                write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
-            }),
+            GenericKind::Alias(ref p) => write!(f, "{:?}", p),
         }
     }
 }
@@ -761,10 +755,7 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             GenericKind::Param(ref p) => write!(f, "{}", p),
-            GenericKind::Projection(ref p) => write!(f, "{}", p),
-            GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
-                write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
-            }),
+            GenericKind::Alias(ref p) => write!(f, "{}", p),
         }
     }
 }
@@ -773,8 +764,7 @@ impl<'tcx> GenericKind<'tcx> {
     pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match *self {
             GenericKind::Param(ref p) => p.to_ty(tcx),
-            GenericKind::Projection(ref p) => tcx.mk_projection(p.def_id, p.substs),
-            GenericKind::Opaque(def_id, substs) => tcx.mk_opaque(def_id, substs),
+            GenericKind::Alias(ref p) => p.to_ty(tcx),
         }
     }
 }
index 8671f8d45a91721d597bb8aa72d514e4dd5027cf..65b90aa3d79d3e285365339e8ec6812c000e09b6 100644 (file)
@@ -147,7 +147,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         } else if !t.has_non_region_infer() {
             // All const/type variables in inference types must already be resolved,
             // no need to visit the contents.
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         } else {
             // Otherwise, keep visiting.
             t.super_visit_with(self)
@@ -178,7 +178,7 @@ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         } else if !ct.has_non_region_infer() {
             // All const/type variables in inference types must already be resolved,
             // no need to visit the contents.
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         } else {
             // Otherwise, keep visiting.
             ct.super_visit_with(self)
index bd38b52ba34a7eab0fbcbae019d94d58dd0d2c40..51c34f0d55f6ff715336cc2b45d53c3e2df19a16 100644 (file)
@@ -191,12 +191,13 @@ fn regions(
         // from the "cause" field, we could perhaps give more tailored
         // error messages.
         let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
+        // Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a)
         self.fields
             .infcx
             .inner
             .borrow_mut()
             .unwrap_region_constraints()
-            .make_subregion(origin, a, b);
+            .make_subregion(origin, b, a);
 
         Ok(a)
     }
index 7ff086452536bbfafa30d80f7a9050f9540eeed6..263c6a47dd2af79f791343f418ca911376d44a52 100644 (file)
@@ -433,7 +433,7 @@ impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> {
     fn unify_values(value1: &Self, value2: &Self) -> Result<Self, ut::NoError> {
         match (value1, value2) {
             // We never equate two type variables, both of which
-            // have known types.  Instead, we recursively equate
+            // have known types. Instead, we recursively equate
             // those types.
             (&TypeVariableValue::Known { .. }, &TypeVariableValue::Known { .. }) => {
                 bug!("equating two type variables, both of which have known types")
index d3519f4b37b8287b254efd802ae4edeaa3b174e5..f75344f20b6d98e842f622dfd3e39d23e8e22385 100644 (file)
@@ -1,6 +1,5 @@
 use crate::infer::InferCtxt;
 use crate::traits::Obligation;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, ToPredicate, Ty};
 
@@ -37,13 +36,19 @@ fn register_predicate_obligation(
         obligation: PredicateObligation<'tcx>,
     );
 
-    fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
-
     fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
 
+    fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>>;
+
     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
 
-    fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships>;
+    /// Among all pending obligations, collect those are stalled on a inference variable which has
+    /// changed since the last call to `select_where_possible`. Those obligations are marked as
+    /// successful and returned.
+    fn drain_unstalled_obligations(
+        &mut self,
+        infcx: &InferCtxt<'tcx>,
+    ) -> Vec<PredicateObligation<'tcx>>;
 }
 
 pub trait TraitEngineExt<'tcx> {
@@ -52,6 +57,8 @@ fn register_predicate_obligations(
         infcx: &InferCtxt<'tcx>,
         obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
     );
+
+    fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
 }
 
 impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
@@ -64,4 +71,13 @@ fn register_predicate_obligations(
             self.register_predicate_obligation(infcx, obligation);
         }
     }
+
+    fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
+        let errors = self.select_where_possible(infcx);
+        if !errors.is_empty() {
+            return errors;
+        }
+
+        self.collect_remaining_errors()
+    }
 }
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 8f0bd3a9abe5e29ac32a3a754f3516790bd9a4c6..cd5bde2a791309c6c0f6d5aa6d73a55e412e0e36 100644 (file)
@@ -1,7 +1,7 @@
 use smallvec::smallvec;
 
 use crate::infer::outlives::components::{push_outlives_components, Component};
-use crate::traits::{Obligation, ObligationCause, PredicateObligation};
+use crate::traits::{self, Obligation, ObligationCause, PredicateObligation};
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_middle::ty::{self, ToPredicate, TyCtxt};
 use rustc_span::symbol::Ident;
@@ -145,16 +145,28 @@ fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
                 // Get predicates declared on the trait.
                 let predicates = tcx.super_predicates_of(data.def_id());
 
-                let obligations = predicates.predicates.iter().map(|&(mut pred, _)| {
+                let obligations = predicates.predicates.iter().map(|&(mut pred, span)| {
                     // when parent predicate is non-const, elaborate it to non-const predicates.
                     if data.constness == ty::BoundConstness::NotConst {
                         pred = pred.without_const(tcx);
                     }
 
+                    let cause = obligation.cause.clone().derived_cause(
+                        bound_predicate.rebind(data),
+                        |derived| {
+                            traits::ImplDerivedObligation(Box::new(
+                                traits::ImplDerivedObligationCause {
+                                    derived,
+                                    impl_def_id: data.def_id(),
+                                    span,
+                                },
+                            ))
+                        },
+                    );
                     predicate_obligation(
                         pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
                         obligation.param_env,
-                        obligation.cause.clone(),
+                        cause,
                     )
                 });
                 debug!(?data, ?obligations, "super_predicates");
@@ -249,23 +261,15 @@ fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
 
                             Component::UnresolvedInferenceVariable(_) => None,
 
-                            Component::Opaque(def_id, substs) => {
-                                let ty = tcx.mk_opaque(def_id, substs);
-                                Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives(
-                                    ty::OutlivesPredicate(ty, r_min),
-                                )))
-                            }
-
-                            Component::Projection(projection) => {
+                            Component::Alias(alias_ty) => {
                                 // We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
                                 // With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
-                                let ty = tcx.mk_projection(projection.def_id, projection.substs);
                                 Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives(
-                                    ty::OutlivesPredicate(ty, r_min),
+                                    ty::OutlivesPredicate(alias_ty.to_ty(tcx), r_min),
                                 )))
                             }
 
-                            Component::EscapingProjection(_) => {
+                            Component::EscapingAlias(_) => {
                                 // We might be able to do more here, but we don't
                                 // want to deal with escaping vars right now.
                                 None
@@ -333,7 +337,7 @@ pub fn transitive_bounds<'tcx>(
 /// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may
 /// define the given associated type `assoc_name`. It uses the
 /// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that
-/// aren't related to `assoc_item`.  This is used when resolving types like `Self::Item` or
+/// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or
 /// `T::Item` and helps to avoid cycle errors (see e.g. #35237).
 pub fn transitive_bounds_that_define_assoc_type<'tcx>(
     tcx: TyCtxt<'tcx>,
index 7f761b005edd0946ce8e406282fa529f899268a5..7a5e45ada3f6a8f9528778435c6496d78980dc65 100644 (file)
 use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_query_impl::QueryCtxt;
 use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilenames};
-use rustc_session::early_error;
 use rustc_session::lint;
 use rustc_session::parse::{CrateConfig, ParseSess};
 use rustc_session::Session;
+use rustc_session::{early_error, CompilerIO};
 use rustc_span::source_map::{FileLoader, FileName};
 use rustc_span::symbol::sym;
 use std::path::PathBuf;
 pub struct Compiler {
     pub(crate) sess: Lrc<Session>,
     codegen_backend: Lrc<Box<dyn CodegenBackend>>,
-    pub(crate) input: Input,
-    pub(crate) input_path: Option<PathBuf>,
-    pub(crate) output_dir: Option<PathBuf>,
-    pub(crate) output_file: Option<PathBuf>,
-    pub(crate) temps_dir: Option<PathBuf>,
     pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
     pub(crate) override_queries:
         Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
@@ -52,18 +47,6 @@ pub fn session(&self) -> &Lrc<Session> {
     pub fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
         &self.codegen_backend
     }
-    pub fn input(&self) -> &Input {
-        &self.input
-    }
-    pub fn output_dir(&self) -> &Option<PathBuf> {
-        &self.output_dir
-    }
-    pub fn output_file(&self) -> &Option<PathBuf> {
-        &self.output_file
-    }
-    pub fn temps_dir(&self) -> &Option<PathBuf> {
-        &self.temps_dir
-    }
     pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> {
         &self.register_lints
     }
@@ -72,14 +55,7 @@ pub fn build_output_filenames(
         sess: &Session,
         attrs: &[ast::Attribute],
     ) -> OutputFilenames {
-        util::build_output_filenames(
-            &self.input,
-            &self.output_dir,
-            &self.output_file,
-            &self.temps_dir,
-            attrs,
-            sess,
-        )
+        util::build_output_filenames(attrs, sess)
     }
 }
 
@@ -244,7 +220,6 @@ pub struct Config {
     pub crate_check_cfg: CheckCfg,
 
     pub input: Input,
-    pub input_path: Option<PathBuf>,
     pub output_dir: Option<PathBuf>,
     pub output_file: Option<PathBuf>,
     pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
@@ -287,12 +262,19 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
             crate::callbacks::setup_callbacks();
 
             let registry = &config.registry;
+
+            let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
             let (mut sess, codegen_backend) = util::create_session(
                 config.opts,
                 config.crate_cfg,
                 config.crate_check_cfg,
                 config.file_loader,
-                config.input_path.clone(),
+                CompilerIO {
+                    input: config.input,
+                    output_dir: config.output_dir,
+                    output_file: config.output_file,
+                    temps_dir,
+                },
                 config.lint_caps,
                 config.make_codegen_backend,
                 registry.clone(),
@@ -302,16 +284,9 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 parse_sess_created(&mut sess.parse_sess);
             }
 
-            let temps_dir = sess.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
-
             let compiler = Compiler {
                 sess: Lrc::new(sess),
                 codegen_backend: Lrc::new(codegen_backend),
-                input: config.input,
-                input_path: config.input_path,
-                output_dir: config.output_dir,
-                output_file: config.output_file,
-                temps_dir,
                 register_lints: config.register_lints,
                 override_queries: config.override_queries,
             };
index 542b638bbd7a40dcb5596aca193092332b93a811..82bc4770b6b471dcd60caa00fea9ed733d7e9d03 100644 (file)
@@ -3,6 +3,7 @@
 #![feature(internal_output_capture)]
 #![feature(thread_spawn_unchecked)]
 #![feature(once_cell)]
+#![feature(try_blocks)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 #![deny(rustc::untranslatable_diagnostic)]
index 50c40206d8026f66626a3ac07b9c1e0c117dbc3d..60b60edd2c8119a9a2cfb1d2377356a8e3fa0275 100644 (file)
 use rustc_borrowck as mir_borrowck;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::parallel;
-use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_errors::{ErrorGuaranteed, PResult};
 use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
-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;
@@ -31,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};
+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};
 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, input: &Input) -> PResult<'a, ast::Crate> {
-    let krate = sess.time("parse_crate", || match input {
+pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> {
+    let krate = sess.time("parse_crate", || match &sess.io.input {
         Input::File(file) => parse_crate_from_file(file, &sess.parse_sess),
         Input::Str { input, name } => {
             parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess)
@@ -549,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],
 ) {
@@ -559,7 +558,7 @@ fn write_out_deps(
     }
     let deps_filename = outputs.path(OutputType::DepInfo);
 
-    let result = (|| -> io::Result<()> {
+    let result: io::Result<()> = try {
         // Build a list of files used to compile the output and
         // write Makefile-compatible dependency rules
         let mut files: Vec<String> = sess
@@ -601,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)?);
@@ -646,9 +644,7 @@ fn write_out_deps(
                 writeln!(file)?;
             }
         }
-
-        Ok(())
-    })();
+    };
 
     match result {
         Ok(_) => {
@@ -664,71 +660,57 @@ fn write_out_deps(
     }
 }
 
-pub fn prepare_outputs(
-    sess: &Session,
-    compiler: &Compiler,
-    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(
-        &compiler.input,
-        &compiler.output_dir,
-        &compiler.output_file,
-        &compiler.temps_dir,
-        &krate.attrs,
-        sess,
-    );
+    let outputs = util::build_output_filenames(&krate.attrs, sess);
 
     let output_paths =
-        generated_output_paths(sess, &outputs, compiler.output_file.is_some(), crate_name);
+        generated_output_paths(sess, &outputs, sess.io.output_file.is_some(), crate_name);
 
     // Ensure the source file isn't accidentally overwritten during compilation.
-    if let Some(ref input_path) = compiler.input_path {
+    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) = compiler.temps_dir {
+    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;
 
     if !only_dep_info {
-        if let Some(ref dir) = compiler.output_dir {
+        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);
@@ -775,11 +757,8 @@ pub fn enter<F, R>(&mut self, f: F) -> R
 pub fn create_global_ctxt<'tcx>(
     compiler: &'tcx Compiler,
     lint_store: Lrc<LintStore>,
-    krate: Lrc<ast::Crate>,
     dep_graph: DepGraph,
-    resolver: Rc<RefCell<BoxedResolver>>,
-    outputs: OutputFilenames,
-    crate_name: Symbol,
+    untracked: Untracked,
     queries: &'tcx OnceCell<TcxQueries<'tcx>>,
     global_ctxt: &'tcx OnceCell<GlobalCtxt<'tcx>>,
     arena: &'tcx WorkerLocal<Arena<'tcx>>,
@@ -790,8 +769,6 @@ pub fn create_global_ctxt<'tcx>(
     // incr. comp. yet.
     dep_graph.assert_ignored();
 
-    let resolver_outputs = BoxedResolver::to_resolver_outputs(resolver);
-
     let sess = &compiler.session();
     let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
 
@@ -810,12 +787,6 @@ pub fn create_global_ctxt<'tcx>(
         TcxQueries::new(local_providers, extern_providers, query_result_on_disk_cache)
     });
 
-    let ty::ResolverOutputs {
-        global_ctxt: untracked_resolutions,
-        ast_lowering: untracked_resolver_for_lowering,
-        untracked,
-    } = resolver_outputs;
-
     let gcx = sess.time("setup_global_ctxt", || {
         global_ctxt.get_or_init(move || {
             TyCtxt::create_global_ctxt(
@@ -832,19 +803,7 @@ pub fn create_global_ctxt<'tcx>(
         })
     });
 
-    let mut qcx = QueryContext { gcx };
-    qcx.enter(|tcx| {
-        let feed = tcx.feed_unit_query();
-        feed.resolver_for_lowering(
-            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(sess.features_untracked());
-        let feed = tcx.feed_local_crate();
-        feed.crate_name(crate_name);
-    });
-    qcx
+    QueryContext { gcx }
 }
 
 /// Runs the resolution, type-checking, region checking and other
@@ -934,6 +893,15 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
         }
     });
 
+    if tcx.sess.opts.unstable_opts.drop_tracking_mir {
+        tcx.hir().par_body_owners(|def_id| {
+            if let rustc_hir::def::DefKind::Generator = tcx.def_kind(def_id) {
+                tcx.ensure().mir_generator_witnesses(def_id);
+                tcx.ensure().check_generator_obligations(def_id);
+            }
+        });
+    }
+
     sess.time("layout_testing", || layout_test::test_layout(tcx));
 
     // Avoid overwhelming user with errors if borrow checking failed.
index 041bb9eb7a1cbcd58b9239fa432b9784334fbc99..4b0180741c19df0af11d84b6c6d388bc5b1ffc42 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_lint::LintStore;
 use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::DepGraph;
-use rustc_middle::ty::{GlobalCtxt, TyCtxt};
+use rustc_middle::ty::{self, GlobalCtxt, TyCtxt};
 use rustc_query_impl::Queries as TcxQueries;
 use rustc_session::config::{self, OutputFilenames, OutputType};
 use rustc_session::{output::find_crate_name, Session};
@@ -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)
     }
 }
@@ -90,7 +90,6 @@ pub struct Queries<'tcx> {
     register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
     expansion: Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>,
     dep_graph: Query<DepGraph>,
-    prepare_outputs: Query<OutputFilenames>,
     global_ctxt: Query<QueryContext<'tcx>>,
     ongoing_codegen: Query<Box<dyn Any>>,
 }
@@ -109,7 +108,6 @@ pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> {
             register_plugins: Default::default(),
             expansion: Default::default(),
             dep_graph: Default::default(),
-            prepare_outputs: Default::default(),
             global_ctxt: Default::default(),
             ongoing_codegen: Default::default(),
         }
@@ -130,10 +128,8 @@ fn dep_graph_future(&self) -> Result<QueryResult<'_, Option<DepGraphFuture>>> {
     }
 
     pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> {
-        self.parse.compute(|| {
-            passes::parse(self.session(), &self.compiler.input)
-                .map_err(|mut parse_error| parse_error.emit())
-        })
+        self.parse
+            .compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit()))
     }
 
     pub fn register_plugins(&self) -> Result<QueryResult<'_, (ast::Crate, Lrc<LintStore>)>> {
@@ -161,13 +157,13 @@ pub fn register_plugins(&self) -> Result<QueryResult<'_, (ast::Crate, Lrc<LintSt
         })
     }
 
-    pub fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> {
+    fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> {
         self.crate_name.compute(|| {
             Ok({
                 let parse_result = self.parse()?;
                 let krate = parse_result.borrow();
                 // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
-                find_crate_name(self.session(), &krate.attrs, &self.compiler.input)
+                find_crate_name(self.session(), &krate.attrs)
             })
         })
     }
@@ -211,40 +207,39 @@ fn dep_graph(&self) -> Result<QueryResult<'_, DepGraph>> {
         })
     }
 
-    pub fn prepare_outputs(&self) -> Result<QueryResult<'_, OutputFilenames>> {
-        self.prepare_outputs.compute(|| {
-            let expansion = self.expansion()?;
-            let (krate, boxed_resolver, _) = &*expansion.borrow();
-            let crate_name = *self.crate_name()?.borrow();
-            passes::prepare_outputs(
-                self.session(),
-                self.compiler,
-                krate,
-                &*boxed_resolver,
-                crate_name,
-            )
-        })
-    }
-
     pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, QueryContext<'tcx>>> {
         self.global_ctxt.compute(|| {
             let crate_name = *self.crate_name()?.borrow();
-            let outputs = self.prepare_outputs()?.steal();
-            let dep_graph = self.dep_graph()?.borrow().clone();
             let (krate, resolver, lint_store) = self.expansion()?.steal();
-            Ok(passes::create_global_ctxt(
+
+            let ty::ResolverOutputs {
+                untracked,
+                global_ctxt: untracked_resolutions,
+                ast_lowering: untracked_resolver_for_lowering,
+            } = BoxedResolver::to_resolver_outputs(resolver);
+
+            let mut qcx = passes::create_global_ctxt(
                 self.compiler,
                 lint_store,
-                krate,
-                dep_graph,
-                resolver,
-                outputs,
-                crate_name,
+                self.dep_graph()?.steal(),
+                untracked,
                 &self.queries,
                 &self.gcx,
                 &self.arena,
                 &self.hir_arena,
-            ))
+            );
+
+            qcx.enter(|tcx| {
+                let feed = tcx.feed_unit_query();
+                feed.resolver_for_lowering(
+                    tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, krate))),
+                );
+                feed.resolutions(tcx.arena.alloc(untracked_resolutions));
+                feed.features_query(tcx.sess.features_untracked());
+                let feed = tcx.feed_local_crate();
+                feed.crate_name(crate_name);
+            });
+            Ok(qcx)
         })
     }
 
index 07b28cc86cee1c95601f320e5ead863001913ab7..52a4e0e74181f78092fb85230051352b995a23ac 100644 (file)
@@ -4,6 +4,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
 use rustc_session::config::rustc_optgroups;
+use rustc_session::config::Input;
 use rustc_session::config::TraitSolver;
 use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
 use rustc_session::config::{
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
 use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
+use rustc_session::CompilerIO;
 use rustc_session::{build_session, getopts, Session};
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::symbol::sym;
+use rustc_span::FileName;
 use rustc_span::SourceFileHashAlgorithm;
 use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
 use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
@@ -39,7 +42,14 @@ fn build_session_options_and_crate_config(matches: getopts::Matches) -> (Options
 fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
     let registry = registry::Registry::new(&[]);
     let (sessopts, cfg) = build_session_options_and_crate_config(matches);
-    let sess = build_session(sessopts, None, None, registry, Default::default(), None, None);
+    let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
+    let io = CompilerIO {
+        input: Input::Str { name: FileName::Custom(String::new()), input: String::new() },
+        output_dir: None,
+        output_file: None,
+        temps_dir,
+    };
+    let sess = build_session(sessopts, io, None, registry, Default::default(), None, None);
     (sess, cfg)
 }
 
@@ -792,6 +802,7 @@ macro_rules! tracked {
     tracked!(teach, true);
     tracked!(thinlto, Some(true));
     tracked!(thir_unsafeck, true);
+    tracked!(tiny_const_eval_limit, true);
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
     tracked!(trait_solver, TraitSolver::Chalk);
     tracked!(translate_remapped_path_to_local_path, false);
index 02a7756c8d4532077cde69573a8c3e49c1b6ba76..54363e07b971a2830c789a7c34336d362e480573 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_session as session;
 use rustc_session::config::CheckCfg;
 use rustc_session::config::{self, CrateType};
-use rustc_session::config::{ErrorOutputType, Input, OutputFilenames};
+use rustc_session::config::{ErrorOutputType, OutputFilenames};
 use rustc_session::filesearch::sysroot_candidates;
 use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::parse::CrateConfig;
@@ -17,6 +17,7 @@
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::FileLoader;
 use rustc_span::symbol::{sym, Symbol};
+use session::CompilerIO;
 use std::env;
 use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
 use std::mem;
@@ -58,7 +59,7 @@ pub fn create_session(
     cfg: FxHashSet<(String, Option<String>)>,
     check_cfg: CheckCfg,
     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
-    input_path: Option<PathBuf>,
+    io: CompilerIO,
     lint_caps: FxHashMap<lint::LintId, lint::Level>,
     make_codegen_backend: Option<
         Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
@@ -89,7 +90,7 @@ pub fn create_session(
 
     let mut sess = session::build_session(
         sopts,
-        input_path,
+        io,
         bundle,
         descriptions,
         lint_caps,
@@ -486,20 +487,13 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<C
     base
 }
 
-pub fn build_output_filenames(
-    input: &Input,
-    odir: &Option<PathBuf>,
-    ofile: &Option<PathBuf>,
-    temps_dir: &Option<PathBuf>,
-    attrs: &[ast::Attribute],
-    sess: &Session,
-) -> OutputFilenames {
-    match *ofile {
+pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> OutputFilenames {
+    match sess.io.output_file {
         None => {
             // "-" as input file will cause the parser to read from stdin so we
             // have to make up a name
             // We want to toss everything after the final '.'
-            let dirpath = (*odir).as_ref().cloned().unwrap_or_default();
+            let dirpath = sess.io.output_dir.clone().unwrap_or_default();
 
             // If a crate name is present, we use it as the link name
             let stem = sess
@@ -507,13 +501,13 @@ pub fn build_output_filenames(
                 .crate_name
                 .clone()
                 .or_else(|| rustc_attr::find_crate_name(sess, attrs).map(|n| n.to_string()))
-                .unwrap_or_else(|| input.filestem().to_owned());
+                .unwrap_or_else(|| sess.io.input.filestem().to_owned());
 
             OutputFilenames::new(
                 dirpath,
                 stem,
                 None,
-                temps_dir.clone(),
+                sess.io.temps_dir.clone(),
                 sess.opts.cg.extra_filename.clone(),
                 sess.opts.output_types.clone(),
             )
@@ -534,7 +528,7 @@ pub fn build_output_filenames(
                 }
                 Some(out_file.clone())
             };
-            if *odir != None {
+            if sess.io.output_dir != None {
                 sess.warn("ignoring --out-dir flag due to -o flag");
             }
 
@@ -542,7 +536,7 @@ pub fn build_output_filenames(
                 out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
                 out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(),
                 ofile,
-                temps_dir.clone(),
+                sess.io.temps_dir.clone(),
                 sess.opts.cg.extra_filename.clone(),
                 sess.opts.output_types.clone(),
             )
index 4c65fca29b89721542148dcfadf447bee9f7048b..6e815863d06ff9e226d6fa1f5bb06fd0152a6e5d 100644 (file)
@@ -2,7 +2,7 @@
 //!
 //! The idea with `rustc_lexer` is to make a reusable library,
 //! by separating out pure lexing and rustc-specific concerns, like spans,
-//! error reporting, and interning.  So, rustc_lexer operates directly on `&str`,
+//! error reporting, and interning. So, rustc_lexer operates directly on `&str`,
 //! produces simple tokens which are a pair of type-tag and a bit of original text,
 //! and does not report errors, instead storing them as flags on the token.
 //!
index 87c44638a8de1918883375cd0d6357dfebd8a16b..8507ca9d89ed776b77228fec41521ab835ce75e3 100644 (file)
@@ -299,7 +299,7 @@ fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut
         let tail = &tail[first_non_space..];
         if let Some(c) = tail.chars().nth(0) {
             // For error reporting, we would like the span to contain the character that was not
-            // skipped.  The +1 is necessary to account for the leading \ that started the escape.
+            // skipped. The +1 is necessary to account for the leading \ that started the escape.
             let end = start + first_non_space + c.len_utf8() + 1;
             if c.is_whitespace() {
                 callback(start..end, Err(EscapeError::UnskippedWhitespaceWarning));
index 6f445426df70e7218c5b1a744a7ca34fdd73e66f..8361c81f0efe35f63d22fe9bc08ce52217e0d2b1 100644 (file)
@@ -56,9 +56,7 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
 use rustc_hir::intravisit::FnKind as HirFnKind;
-use rustc_hir::{
-    Body, FnDecl, ForeignItemKind, GenericParamKind, HirId, Node, PatKind, PredicateOrigin,
-};
+use rustc_hir::{Body, FnDecl, ForeignItemKind, GenericParamKind, Node, PatKind, PredicateOrigin};
 use rustc_index::vec::Idx;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf};
@@ -72,7 +70,7 @@
 use rustc_span::{BytePos, InnerSpan, Span};
 use rustc_target::abi::{Abi, VariantIdx};
 use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
-use rustc_trait_selection::traits::{self, misc::can_type_implement_copy, EvaluationResult};
+use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy};
 
 use crate::nonstandard_style::{method_context, MethodLateContext};
 
@@ -583,12 +581,13 @@ fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
         // If the method is an impl for a trait, don't doc.
-        if method_context(cx, impl_item.hir_id()) == MethodLateContext::TraitImpl {
+        let context = method_context(cx, impl_item.owner_id.def_id);
+        if context == MethodLateContext::TraitImpl {
             return;
         }
 
         // If the method is an impl for an item with docs_hidden, don't doc.
-        if method_context(cx, impl_item.hir_id()) == MethodLateContext::PlainImpl {
+        if context == MethodLateContext::PlainImpl {
             let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
             let impl_ty = cx.tcx.type_of(parent);
             let outerdef = match impl_ty.kind() {
@@ -709,12 +708,14 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
 
         // We shouldn't recommend implementing `Copy` on stateful things,
         // such as iterators.
-        if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) {
-            if cx.tcx.infer_ctxt().build().type_implements_trait(iter_trait, [ty], param_env)
-                == EvaluationResult::EvaluatedToOk
-            {
-                return;
-            }
+        if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
+            && cx.tcx
+                .infer_ctxt()
+                .build()
+                .type_implements_trait(iter_trait, [ty], param_env)
+                .must_apply_modulo_regions()
+        {
+            return;
         }
 
         // Default value of clippy::trivially_copy_pass_by_ref
@@ -726,11 +727,11 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
             }
         }
 
-        if can_type_implement_copy(
+        if type_allowed_to_implement_copy(
             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()
         {
@@ -1294,19 +1295,18 @@ fn check_fn(
         _: &'tcx FnDecl<'_>,
         _: &'tcx Body<'_>,
         span: Span,
-        hir_id: HirId,
+        def_id: LocalDefId,
     ) {
         if fn_kind.asyncness() == IsAsync::Async
             && !cx.tcx.features().closure_track_caller
-            && let attrs = cx.tcx.hir().attrs(hir_id)
             // Now, check if the function has the `#[track_caller]` attribute
-            && let Some(attr) = attrs.iter().find(|attr| attr.has_name(sym::track_caller))
-            {
-                cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller {
-                    label: span,
-                    parse_sess: &cx.tcx.sess.parse_sess,
-                });
-            }
+            && let Some(attr) = cx.tcx.get_attr(def_id.to_def_id(), sym::track_caller)
+        {
+            cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller {
+                label: span,
+                parse_sess: &cx.tcx.sess.parse_sess,
+            });
+        }
     }
 }
 
@@ -2173,13 +2173,31 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                     dropped_predicate_count += 1;
                 }
 
-                if drop_predicate && !in_where_clause {
-                    lint_spans.push(predicate_span);
-                } else if drop_predicate && i + 1 < num_predicates {
-                    // If all the bounds on a predicate were inferable and there are
-                    // further predicates, we want to eat the trailing comma.
-                    let next_predicate_span = hir_generics.predicates[i + 1].span();
-                    where_lint_spans.push(predicate_span.to(next_predicate_span.shrink_to_lo()));
+                if drop_predicate {
+                    if !in_where_clause {
+                        lint_spans.push(predicate_span);
+                    } else if predicate_span.from_expansion() {
+                        // Don't try to extend the span if it comes from a macro expansion.
+                        where_lint_spans.push(predicate_span);
+                    } else if i + 1 < num_predicates {
+                        // If all the bounds on a predicate were inferable and there are
+                        // further predicates, we want to eat the trailing comma.
+                        let next_predicate_span = hir_generics.predicates[i + 1].span();
+                        if next_predicate_span.from_expansion() {
+                            where_lint_spans.push(predicate_span);
+                        } else {
+                            where_lint_spans
+                                .push(predicate_span.to(next_predicate_span.shrink_to_lo()));
+                        }
+                    } else {
+                        // Eat the optional trailing comma after the last predicate.
+                        let where_span = hir_generics.where_clause_span;
+                        if where_span.from_expansion() {
+                            where_lint_spans.push(predicate_span);
+                        } else {
+                            where_lint_spans.push(predicate_span.to(where_span.shrink_to_hi()));
+                        }
+                    }
                 } else {
                     where_lint_spans.extend(self.consolidate_outlives_bound_spans(
                         predicate_span.shrink_to_lo(),
@@ -2223,6 +2241,11 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                     Applicability::MaybeIncorrect
                 };
 
+                // Due to macros, there might be several predicates with the same span
+                // and we only want to suggest removing them once.
+                lint_spans.sort_unstable();
+                lint_spans.dedup();
+
                 cx.emit_spanned_lint(
                     EXPLICIT_OUTLIVES_REQUIREMENTS,
                     lint_spans.clone(),
@@ -2659,7 +2682,7 @@ pub struct ClashingExternDeclarations {
     /// the symbol should be reported as a clashing declaration.
     // FIXME: Technically, we could just store a &'tcx str here without issue; however, the
     // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime.
-    seen_decls: FxHashMap<Symbol, HirId>,
+    seen_decls: FxHashMap<Symbol, hir::OwnerId>,
 }
 
 /// Differentiate between whether the name for an extern decl came from the link_name attribute or
@@ -2685,19 +2708,20 @@ impl ClashingExternDeclarations {
     pub(crate) fn new() -> Self {
         ClashingExternDeclarations { seen_decls: FxHashMap::default() }
     }
+
     /// Insert a new foreign item into the seen set. If a symbol with the same name already exists
     /// for the item, return its HirId without updating the set.
-    fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> {
+    fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<hir::OwnerId> {
         let did = fi.owner_id.to_def_id();
         let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
         let name = Symbol::intern(tcx.symbol_name(instance).name);
-        if let Some(&hir_id) = self.seen_decls.get(&name) {
+        if let Some(&existing_id) = self.seen_decls.get(&name) {
             // Avoid updating the map with the new entry when we do find a collision. We want to
             // make sure we're always pointing to the first definition as the previous declaration.
             // This lets us avoid emitting "knock-on" diagnostics.
-            Some(hir_id)
+            Some(existing_id)
         } else {
-            self.seen_decls.insert(name, fi.hir_id())
+            self.seen_decls.insert(name, fi.owner_id)
         }
     }
 
@@ -2924,16 +2948,16 @@ fn structurally_same_type_impl<'tcx>(
 impl_lint_pass!(ClashingExternDeclarations => [CLASHING_EXTERN_DECLARATIONS]);
 
 impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
+    #[instrument(level = "trace", skip(self, cx))]
     fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignItem<'_>) {
-        trace!("ClashingExternDeclarations: check_foreign_item: {:?}", this_fi);
         if let ForeignItemKind::Fn(..) = this_fi.kind {
             let tcx = cx.tcx;
-            if let Some(existing_hid) = self.insert(tcx, this_fi) {
-                let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid));
+            if let Some(existing_did) = self.insert(tcx, this_fi) {
+                let existing_decl_ty = tcx.type_of(existing_did);
                 let this_decl_ty = tcx.type_of(this_fi.owner_id);
                 debug!(
                     "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
-                    existing_hid, existing_decl_ty, this_fi.owner_id, this_decl_ty
+                    existing_did, existing_decl_ty, this_fi.owner_id, this_decl_ty
                 );
                 // Check that the declarations match.
                 if !Self::structurally_same_type(
@@ -2942,7 +2966,7 @@ fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignI
                     this_decl_ty,
                     CItemKind::Declaration,
                 ) {
-                    let orig_fi = tcx.hir().expect_foreign_item(existing_hid.expect_owner());
+                    let orig_fi = tcx.hir().expect_foreign_item(existing_did);
                     let orig = Self::name_of_extern_decl(tcx, orig_fi);
 
                     // We want to ensure that we use spans for both decls that include where the
index c9b9a62257148c51a8614717ade5d77b03cf30d1..8046cc21cea583eb73f15cb45228593a05139af6 100644 (file)
@@ -825,21 +825,24 @@ fn lookup_with_diagnostics(
                     debug!(?param_span, ?use_span, ?deletion_span);
                     db.span_label(param_span, "this lifetime...");
                     db.span_label(use_span, "...is used only here");
-                    let msg = "elide the single-use lifetime";
-                    let (use_span, replace_lt) = if elide {
-                        let use_span = sess.source_map().span_extend_while(
-                            use_span,
-                            char::is_whitespace,
-                        ).unwrap_or(use_span);
-                        (use_span, String::new())
-                    } else {
-                        (use_span, "'_".to_owned())
-                    };
-                    db.multipart_suggestion(
-                        msg,
-                        vec![(deletion_span, String::new()), (use_span, replace_lt)],
-                        Applicability::MachineApplicable,
-                    );
+                    if let Some(deletion_span) = deletion_span {
+                        let msg = "elide the single-use lifetime";
+                        let (use_span, replace_lt) = if elide {
+                            let use_span = sess.source_map().span_extend_while(
+                                use_span,
+                                char::is_whitespace,
+                            ).unwrap_or(use_span);
+                            (use_span, String::new())
+                        } else {
+                            (use_span, "'_".to_owned())
+                        };
+                        debug!(?deletion_span, ?use_span);
+                        db.multipart_suggestion(
+                            msg,
+                            vec![(deletion_span, String::new()), (use_span, replace_lt)],
+                            Applicability::MachineApplicable,
+                        );
+                    }
                 },
                 BuiltinLintDiagnostics::SingleUseLifetime {
                     param_span: _,
@@ -847,12 +850,14 @@ fn lookup_with_diagnostics(
                     deletion_span,
                 } => {
                     debug!(?deletion_span);
-                    db.span_suggestion(
-                        deletion_span,
-                        "elide the unused lifetime",
-                        "",
-                        Applicability::MachineApplicable,
-                    );
+                    if let Some(deletion_span) = deletion_span {
+                        db.span_suggestion(
+                            deletion_span,
+                            "elide the unused lifetime",
+                            "",
+                            Applicability::MachineApplicable,
+                        );
+                    }
                 },
                 BuiltinLintDiagnostics::NamedArgumentUsedPositionally{ position_sp_to_replace, position_sp_for_msg, named_arg_sp, named_arg_name, is_formatting_arg} => {
                     db.span_label(named_arg_sp, "this named argument is referred to by position in formatting string");
index f9b2df49592244fa701928bfbe71eeac0357df41..337a19dd024d2fec195601c77de253036df847bf 100644 (file)
@@ -248,7 +248,9 @@ fn visit_generics(&mut self, g: &'a ast::Generics) {
     }
 
     fn visit_where_predicate(&mut self, p: &'a ast::WherePredicate) {
+        lint_callback!(self, enter_where_predicate, p);
         ast_visit::walk_where_predicate(self, p);
+        lint_callback!(self, exit_where_predicate, p);
     }
 
     fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) {
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 5eb54cc0034279392c1eac3a4cdf8ad6b7d78b80..6cefaea2bc7da8af59508ff2cad32366ccce9d54 100644 (file)
@@ -187,9 +187,9 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
                         },
                         None => cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag),
                     }
-                } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
+                } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(ty) = is_ty_or_ty_ctxt(cx, &path) {
                     cx.emit_spanned_lint(USAGE_OF_QUALIFIED_TY, path.span, TyQualified {
-                        ty: t.clone(),
+                        ty,
                         suggestion: path.span,
                     });
                 }
index b2a2656746eec8b45849ec4faf9ce905ef15ec69..b42878a02ee02985408d41e21ac7efd4aaf7392a 100644 (file)
@@ -66,13 +66,12 @@ fn with_lint_attrs<F>(&mut self, id: hir::HirId, f: F)
         self.context.last_node_with_lint_attrs = prev;
     }
 
-    fn with_param_env<F>(&mut self, id: hir::HirId, f: F)
+    fn with_param_env<F>(&mut self, id: hir::OwnerId, f: F)
     where
         F: FnOnce(&mut Self),
     {
         let old_param_env = self.context.param_env;
-        self.context.param_env =
-            self.context.tcx.param_env(self.context.tcx.hir().local_def_id(id));
+        self.context.param_env = self.context.tcx.param_env(id);
         f(self);
         self.context.param_env = old_param_env;
     }
@@ -132,7 +131,7 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
         let old_cached_typeck_results = self.context.cached_typeck_results.take();
         let old_enclosing_body = self.context.enclosing_body.take();
         self.with_lint_attrs(it.hir_id(), |cx| {
-            cx.with_param_env(it.hir_id(), |cx| {
+            cx.with_param_env(it.owner_id, |cx| {
                 lint_callback!(cx, check_item, it);
                 hir_visit::walk_item(cx, it);
                 lint_callback!(cx, check_item_post, it);
@@ -145,7 +144,7 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
 
     fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
         self.with_lint_attrs(it.hir_id(), |cx| {
-            cx.with_param_env(it.hir_id(), |cx| {
+            cx.with_param_env(it.owner_id, |cx| {
                 lint_callback!(cx, check_foreign_item, it);
                 hir_visit::walk_foreign_item(cx, it);
             });
@@ -180,7 +179,7 @@ fn visit_fn(
         decl: &'tcx hir::FnDecl<'tcx>,
         body_id: hir::BodyId,
         span: Span,
-        id: hir::HirId,
+        id: LocalDefId,
     ) {
         // Wrap in typeck results here, not just in visit_nested_body,
         // in order for `check_fn` to be able to use them.
@@ -268,7 +267,7 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         let generics = self.context.generics.take();
         self.context.generics = Some(&trait_item.generics);
         self.with_lint_attrs(trait_item.hir_id(), |cx| {
-            cx.with_param_env(trait_item.hir_id(), |cx| {
+            cx.with_param_env(trait_item.owner_id, |cx| {
                 lint_callback!(cx, check_trait_item, trait_item);
                 hir_visit::walk_trait_item(cx, trait_item);
             });
@@ -280,7 +279,7 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         let generics = self.context.generics.take();
         self.context.generics = Some(&impl_item.generics);
         self.with_lint_attrs(impl_item.hir_id(), |cx| {
-            cx.with_param_env(impl_item.hir_id(), |cx| {
+            cx.with_param_env(impl_item.owner_id, |cx| {
                 lint_callback!(cx, check_impl_item, impl_item);
                 hir_visit::walk_impl_item(cx, impl_item);
                 lint_callback!(cx, check_impl_item_post, impl_item);
index 09dfb1022d857205b5699e6f9b46a2843d5efb29..cca36913dea113650269b7376a8bef5b31da5c31 100644 (file)
@@ -50,7 +50,7 @@ struct LintStackIndex {
     }
 }
 
-/// Specifications found at this position in the stack.  This map only represents the lints
+/// Specifications found at this position in the stack. This map only represents the lints
 /// found for one set of attributes (like `shallow_lint_levels_on` does).
 ///
 /// We store the level specifications as a linked list.
@@ -163,7 +163,7 @@ fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLe
     match attrs.map.range(..) {
         // There is only something to do if there are attributes at all.
         [] => {}
-        // Most of the time, there is only one attribute.  Avoid fetching HIR in that case.
+        // Most of the time, there is only one attribute. Avoid fetching HIR in that case.
         [(local_id, _)] => levels.add_id(HirId { owner, local_id: *local_id }),
         // Otherwise, we need to visit the attributes in source code order, so we fetch HIR and do
         // a standard visit.
index 3d818154cb94ff48c1a7c33fd2a19d473b089588..ba15dbd86cfa4caff089c597a84391a69ff7a400 100644 (file)
@@ -64,6 +64,7 @@
 mod levels;
 mod lints;
 mod methods;
+mod multiple_supertrait_upcastable;
 mod non_ascii_idents;
 mod non_fmt_panic;
 mod nonstandard_style;
@@ -98,6 +99,7 @@
 use internal::*;
 use let_underscore::*;
 use methods::*;
+use multiple_supertrait_upcastable::*;
 use non_ascii_idents::*;
 use non_fmt_panic::NonPanicFmt;
 use nonstandard_style::*;
@@ -145,7 +147,7 @@ fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     [
         pub BuiltinCombinedEarlyLintPass,
         [
-            UnusedParens: UnusedParens,
+            UnusedParens: UnusedParens::new(),
             UnusedBraces: UnusedBraces,
             UnusedImportBraces: UnusedImportBraces,
             UnsafeCode: UnsafeCode,
@@ -232,6 +234,7 @@ fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
             InvalidAtomicOrdering: InvalidAtomicOrdering,
             NamedAsmLabels: NamedAsmLabels,
             OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
+            MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
         ]
     ]
 );
index c3782a496891db3797bab13879bc32e54f024d02..0c1019545f382f8a5ce425a871a5aa1cc225f149 100644 (file)
@@ -277,7 +277,7 @@ fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
         ) -> rustc_errors::SubdiagnosticMessage,
     {
         // Access to associates types should use `<T as Bound>::Assoc`, which does not need a
-        // bound.  Let's see if this type does that.
+        // bound. Let's see if this type does that.
 
         // We use a HIR visitor to walk the type.
         use rustc_hir::intravisit::{self, Visitor};
@@ -917,6 +917,13 @@ pub struct CStringPtr {
     pub unwrap: Span,
 }
 
+// multiple_supertrait_upcastable.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_multple_supertrait_upcastable)]
+pub struct MultipleSupertraitUpcastable {
+    pub ident: Ident,
+}
+
 // non_ascii_idents.rs
 #[derive(LintDiagnostic)]
 #[diag(lint_identifier_non_ascii_char)]
diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
new file mode 100644 (file)
index 0000000..c2ed0e1
--- /dev/null
@@ -0,0 +1,60 @@
+use crate::{LateContext, LateLintPass, LintContext};
+
+use rustc_hir as hir;
+use rustc_span::sym;
+
+declare_lint! {
+    /// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple
+    /// supertraits.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// trait A {}
+    /// trait B {}
+    ///
+    /// #[warn(multiple_supertrait_upcastable)]
+    /// trait C: A + B {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// To support upcasting with multiple supertraits, we need to store multiple vtables and this
+    /// can result in extra space overhead, even if no code actually uses upcasting.
+    /// This lint allows users to identify when such scenarios occur and to decide whether the
+    /// additional overhead is justified.
+    pub MULTIPLE_SUPERTRAIT_UPCASTABLE,
+    Allow,
+    "detect when an object-safe trait has multiple supertraits",
+    @feature_gate = sym::multiple_supertrait_upcastable;
+}
+
+declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]);
+
+impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
+        let def_id = item.owner_id.to_def_id();
+        // NOTE(nbdd0121): use `object_safety_violations` instead of `check_is_object_safe` because
+        // the latter will report `where_clause_object_safety` lint.
+        if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind
+            && cx.tcx.object_safety_violations(def_id).is_empty()
+        {
+            let direct_super_traits_iter = cx.tcx
+                    .super_predicates_of(def_id)
+                    .predicates
+                    .into_iter()
+                    .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred());
+            if direct_super_traits_iter.count() > 1 {
+                cx.emit_spanned_lint(
+                    MULTIPLE_SUPERTRAIT_UPCASTABLE,
+                    cx.tcx.def_span(def_id),
+                    crate::lints::MultipleSupertraitUpcastable {
+                        ident: item.ident
+                    },
+                );
+            }
+        }
+    }
+}
index 74d234fabea0872467d98c5828b39e472ddc9e0f..71e2e66bdebc2786b0459478b5bfa7b54954a222 100644 (file)
@@ -10,8 +10,9 @@
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{GenericParamKind, PatKind};
 use rustc_middle::ty;
-use rustc_span::symbol::sym;
-use rustc_span::{symbol::Ident, BytePos, Span};
+use rustc_span::def_id::LocalDefId;
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::{BytePos, Span};
 use rustc_target::spec::abi::Abi;
 
 #[derive(PartialEq)]
@@ -21,9 +22,8 @@ pub enum MethodLateContext {
     PlainImpl,
 }
 
-pub fn method_context(cx: &LateContext<'_>, id: hir::HirId) -> MethodLateContext {
-    let def_id = cx.tcx.hir().local_def_id(id);
-    let item = cx.tcx.associated_item(def_id);
+pub fn method_context(cx: &LateContext<'_>, id: LocalDefId) -> MethodLateContext {
+    let item = cx.tcx.associated_item(id);
     match item.container {
         ty::TraitContainer => MethodLateContext::TraitAutoImpl,
         ty::ImplContainer => match cx.tcx.impl_trait_ref(item.container_id(cx.tcx)) {
@@ -379,13 +379,13 @@ fn check_fn(
         _: &hir::FnDecl<'_>,
         _: &hir::Body<'_>,
         _: Span,
-        id: hir::HirId,
+        id: LocalDefId,
     ) {
-        let attrs = cx.tcx.hir().attrs(id);
         match &fk {
             FnKind::Method(ident, sig, ..) => match method_context(cx, id) {
                 MethodLateContext::PlainImpl => {
-                    if sig.header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle)
+                    if sig.header.abi != Abi::Rust
+                        && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle)
                     {
                         return;
                     }
@@ -398,7 +398,7 @@ fn check_fn(
             },
             FnKind::ItemFn(ident, _, header) => {
                 // Skip foreign-ABI #[no_mangle] functions (Issue #31924)
-                if header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle) {
+                if header.abi != Abi::Rust && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle) {
                     return;
                 }
                 self.check_snake_case(cx, "function", ident);
index 57482a9edba880761fd97b38a0b4dc567aba419d..392e13f2fa94165d802ac24c0913934dd5d43d1b 100644 (file)
@@ -32,7 +32,7 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
                     cx.emit_spanned_lint(
                         PASS_BY_VALUE,
                         ty.span,
-                        PassByValueDiag { ty: t.clone(), suggestion: ty.span },
+                        PassByValueDiag { ty: t, suggestion: ty.span },
                     );
                 }
             }
index 5558156a4b9ef040a07ff54271328b64f31e2ba4..16964565b010328935a346de5052081512758374 100644 (file)
@@ -4,6 +4,7 @@
 use rustc_hir as hir;
 use rustc_session::lint::builtin::HardwiredLints;
 use rustc_session::lint::LintPass;
+use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
@@ -36,7 +37,7 @@ fn check_fn(
                 b: &'tcx hir::FnDecl<'tcx>,
                 c: &'tcx hir::Body<'tcx>,
                 d: Span,
-                e: hir::HirId);
+                e: LocalDefId);
             fn check_trait_item(a: &'tcx hir::TraitItem<'tcx>);
             fn check_impl_item(a: &'tcx hir::ImplItem<'tcx>);
             fn check_impl_item_post(a: &'tcx hir::ImplItem<'tcx>);
@@ -171,6 +172,9 @@ macro_rules! early_lint_methods {
 
             /// Counterpart to `enter_lint_attrs`.
             fn exit_lint_attrs(a: &[ast::Attribute]);
+
+            fn enter_where_predicate(a: &ast::WherePredicate);
+            fn exit_where_predicate(a: &ast::WherePredicate);
         ]);
     )
 }
index f2ab44ac97c838410338ee687e3a434f81c2eb43..b0a5d3674ad2795d75fdcefe041c68c2db19f7de 100644 (file)
@@ -14,6 +14,7 @@
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
@@ -1107,6 +1108,7 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
             | ty::Closure(..)
             | ty::Generator(..)
             | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..)
             | ty::Placeholder(..)
             | ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
         }
@@ -1147,7 +1149,7 @@ impl<'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueTypes {
 
             fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if !ty.has_opaque_types() {
-                    return ControlFlow::CONTINUE;
+                    return ControlFlow::Continue(());
                 }
 
                 if let ty::Alias(ty::Opaque, ..) = ty.kind() {
@@ -1223,9 +1225,8 @@ fn check_type_for_ffi_and_report_errors(
         }
     }
 
-    fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl<'_>) {
-        let def_id = self.cx.tcx.hir().local_def_id(id);
-        let sig = self.cx.tcx.fn_sig(def_id);
+    fn check_foreign_fn(&mut self, def_id: LocalDefId, decl: &hir::FnDecl<'_>) {
+        let sig = self.cx.tcx.fn_sig(def_id).subst_identity();
         let sig = self.cx.tcx.erase_late_bound_regions(sig);
 
         for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
@@ -1238,9 +1239,8 @@ fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl<'_>) {
         }
     }
 
-    fn check_foreign_static(&mut self, id: hir::HirId, span: Span) {
-        let def_id = self.cx.tcx.hir().local_def_id(id);
-        let ty = self.cx.tcx.type_of(def_id);
+    fn check_foreign_static(&mut self, id: hir::OwnerId, span: Span) {
+        let ty = self.cx.tcx.type_of(id);
         self.check_type_for_ffi_and_report_errors(span, ty, true, false);
     }
 
@@ -1260,10 +1260,10 @@ fn check_foreign_item(&mut self, cx: &LateContext<'_>, it: &hir::ForeignItem<'_>
         if !vis.is_internal_abi(abi) {
             match it.kind {
                 hir::ForeignItemKind::Fn(ref decl, _, _) => {
-                    vis.check_foreign_fn(it.hir_id(), decl);
+                    vis.check_foreign_fn(it.owner_id.def_id, decl);
                 }
                 hir::ForeignItemKind::Static(ref ty, _) => {
-                    vis.check_foreign_static(it.hir_id(), ty.span);
+                    vis.check_foreign_static(it.owner_id, ty.span);
                 }
                 hir::ForeignItemKind::Type => (),
             }
@@ -1279,7 +1279,7 @@ fn check_fn(
         decl: &'tcx hir::FnDecl<'_>,
         _: &'tcx hir::Body<'_>,
         _: Span,
-        hir_id: hir::HirId,
+        id: LocalDefId,
     ) {
         use hir::intravisit::FnKind;
 
@@ -1291,7 +1291,7 @@ fn check_fn(
 
         let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition };
         if !vis.is_internal_abi(abi) {
-            vis.check_foreign_fn(hir_id, decl);
+            vis.check_foreign_fn(id, decl);
         }
     }
 }
index ac2b32b44e6a1d42e16ab70e7f41872df229b829..4c9b3df2dbd33d706d04c3cc5e911ceeb9c70a2c 100644 (file)
@@ -824,7 +824,17 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
     "`if`, `match`, `while` and `return` do not need parentheses"
 }
 
-declare_lint_pass!(UnusedParens => [UNUSED_PARENS]);
+pub struct UnusedParens {
+    with_self_ty_parens: bool,
+}
+
+impl UnusedParens {
+    pub fn new() -> Self {
+        Self { with_self_ty_parens: false }
+    }
+}
+
+impl_lint_pass!(UnusedParens => [UNUSED_PARENS]);
 
 impl UnusedDelimLint for UnusedParens {
     const DELIM_STR: &'static str = "parentheses";
@@ -999,36 +1009,58 @@ fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
     }
 
     fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
-        if let ast::TyKind::Paren(r) = &ty.kind {
-            match &r.kind {
-                ast::TyKind::TraitObject(..) => {}
-                ast::TyKind::BareFn(b) if b.generic_params.len() > 0 => {}
-                ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
-                ast::TyKind::Array(_, len) => {
-                    self.check_unused_delims_expr(
-                        cx,
-                        &len.value,
-                        UnusedDelimsCtx::ArrayLenExpr,
-                        false,
-                        None,
-                        None,
-                    );
-                }
-                _ => {
-                    let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) {
-                        Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
-                    } else {
-                        None
-                    };
-                    self.emit_unused_delims(cx, ty.span, spans, "type", (false, false));
+        match &ty.kind {
+            ast::TyKind::Array(_, len) => {
+                self.check_unused_delims_expr(
+                    cx,
+                    &len.value,
+                    UnusedDelimsCtx::ArrayLenExpr,
+                    false,
+                    None,
+                    None,
+                );
+            }
+            ast::TyKind::Paren(r) => {
+                match &r.kind {
+                    ast::TyKind::TraitObject(..) => {}
+                    ast::TyKind::BareFn(b)
+                        if self.with_self_ty_parens && b.generic_params.len() > 0 => {}
+                    ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
+                    _ => {
+                        let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) {
+                            Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
+                        } else {
+                            None
+                        };
+                        self.emit_unused_delims(cx, ty.span, spans, "type", (false, false));
+                    }
                 }
+                self.with_self_ty_parens = false;
             }
+            _ => {}
         }
     }
 
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
         <Self as UnusedDelimLint>::check_item(self, cx, item)
     }
+
+    fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) {
+        use rustc_ast::{WhereBoundPredicate, WherePredicate};
+        if let WherePredicate::BoundPredicate(WhereBoundPredicate {
+                bounded_ty,
+                bound_generic_params,
+                ..
+            }) = pred &&
+            let ast::TyKind::Paren(_) = &bounded_ty.kind &&
+            bound_generic_params.is_empty() {
+                self.with_self_ty_parens = true;
+        }
+    }
+
+    fn exit_where_predicate(&mut self, _: &EarlyContext<'_>, _: &ast::WherePredicate) {
+        assert!(!self.with_self_ty_parens);
+    }
 }
 
 declare_lint! {
@@ -1095,14 +1127,19 @@ fn check_unused_delims_expr(
                 //      ```
                 // - the block has no attribute and was not created inside a macro
                 // - if the block is an `anon_const`, the inner expr must be a literal
-                //      (do not lint `struct A<const N: usize>; let _: A<{ 2 + 3 }>;`)
-                //
+                //   not created by a macro, i.e. do not lint on:
+                //      ```
+                //      struct A<const N: usize>;
+                //      let _: A<{ 2 + 3 }>;
+                //      let _: A<{produces_literal!()}>;
+                //      ```
                 // FIXME(const_generics): handle paths when #67075 is fixed.
                 if let [stmt] = inner.stmts.as_slice() {
                     if let ast::StmtKind::Expr(ref expr) = stmt.kind {
                         if !Self::is_expr_delims_necessary(expr, followed_by_block, false)
                             && (ctx != UnusedDelimsCtx::AnonConst
-                                || matches!(expr.kind, ast::ExprKind::Lit(_)))
+                                || (matches!(expr.kind, ast::ExprKind::Lit(_))
+                                    && !expr.span.from_expansion()))
                             && !cx.sess().source_map().is_multiline(value.span)
                             && value.attrs.is_empty()
                             && !value.span.from_expansion()
index 6cdf50970836a99ab5a7c73033a5d68ff202c0bd..4a38ab2159fddcd76f68e494f8f07b2ce4c2a147 100644 (file)
     ///
     /// ### Example
     ///
-    /// ```rust
+    /// ```rust,compile_fail
     /// pub enum Enum {
     ///     Foo,
     ///     Bar,
     /// [identifier pattern]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns
     /// [path pattern]: https://doc.rust-lang.org/reference/patterns.html#path-patterns
     pub BINDINGS_WITH_VARIANT_NAME,
-    Warn,
+    Deny,
     "detects pattern bindings with the same name as one of the matched variants"
 }
 
     };
 }
 
+declare_lint! {
+    /// The `proc_macro_derive_resolution_fallback` lint detects proc macro
+    /// derives using inaccessible names from parent modules.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (proc-macro)
+    /// // foo.rs
+    /// #![crate_type = "proc-macro"]
+    ///
+    /// extern crate proc_macro;
+    ///
+    /// use proc_macro::*;
+    ///
+    /// #[proc_macro_derive(Foo)]
+    /// pub fn foo1(a: TokenStream) -> TokenStream {
+    ///     drop(a);
+    ///     "mod __bar { static mut BAR: Option<Something> = None; }".parse().unwrap()
+    /// }
+    /// ```
+    ///
+    /// ```rust,ignore (needs-dependency)
+    /// // bar.rs
+    /// #[macro_use]
+    /// extern crate foo;
+    ///
+    /// struct Something;
+    ///
+    /// #[derive(Foo)]
+    /// struct Another;
+    ///
+    /// fn main() {}
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: cannot find type `Something` in this scope
+    ///  --> src/main.rs:8:10
+    ///   |
+    /// 8 | #[derive(Foo)]
+    ///   |          ^^^ names from parent modules are not accessible without an explicit import
+    ///   |
+    ///   = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
+    ///   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    ///   = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// If a proc-macro generates a module, the compiler unintentionally
+    /// allowed items in that module to refer to items in the crate root
+    /// without importing them. This is a [future-incompatible] lint to
+    /// transition this to a hard error in the future. See [issue #50504] for
+    /// more details.
+    ///
+    /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
+    Deny,
+    "detects proc macro derives using inaccessible names from parent modules",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
+    };
+}
+
 declare_lint! {
     /// The `macro_use_extern_crate` lint detects the use of the
     /// [`macro_use` attribute].
     "trailing semicolon in macro body used as expression",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #79813 <https://github.com/rust-lang/rust/issues/79813>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
 
         UNSTABLE_NAME_COLLISIONS,
         IRREFUTABLE_LET_PATTERNS,
         WHERE_CLAUSES_OBJECT_SAFETY,
+        PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
         MACRO_USE_EXTERN_CRATE,
         MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
         ILL_FORMED_ATTRIBUTE_INPUT,
     ///
     /// ### Explanation
     ///
-    /// Previously, there were very like checks being performed on `#[doc(..)]`
-    /// unlike the other attributes. It'll now catch all the issues that it
-    /// silently ignored previously.
+    /// Previously, incorrect usage of the `#[doc(..)]` attribute was not
+    /// being validated. Usually these should be rejected as a hard error,
+    /// but this lint was introduced to avoid breaking any existing
+    /// crates which included them.
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard
+    /// error in the future. See [issue #82730] for more details.
+    ///
+    /// [issue #82730]: https://github.com/rust-lang/rust/issues/82730
     pub INVALID_DOC_ATTRIBUTES,
     Warn,
     "detects invalid `#[doc(...)]` attributes",
index f4b4c5168bfd6c392b2c6c0b4cf3f53fcf2e9d09..7054d1e9f105e4392e513f197f3dc91d0632fe2c 100644 (file)
@@ -6,8 +6,9 @@
 extern crate rustc_macros;
 
 pub use self::Level::*;
-use rustc_ast::node_id::{NodeId, NodeMap};
+use rustc_ast::node_id::NodeId;
 use rustc_ast::{AttrId, Attribute};
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_error_messages::{DiagnosticMessage, MultiSpan};
 use rustc_hir::HashStableContext;
@@ -502,7 +503,7 @@ pub enum BuiltinLintDiagnostics {
         param_span: Span,
         /// Span of the code that should be removed when eliding this lifetime.
         /// This span should include leading or trailing comma.
-        deletion_span: Span,
+        deletion_span: Option<Span>,
         /// Span of the single use, or None if the lifetime is never used.
         /// If true, the lifetime will be fully elided.
         use_span: Option<(Span, bool)>,
@@ -544,7 +545,7 @@ pub struct BufferedEarlyLint {
 
 #[derive(Default)]
 pub struct LintBuffer {
-    pub map: NodeMap<Vec<BufferedEarlyLint>>,
+    pub map: FxIndexMap<NodeId, Vec<BufferedEarlyLint>>,
 }
 
 impl LintBuffer {
index 2865ea8927336143490193bddbeaec125dda6789..f728bff0e3b91a3a1665ae58eab72654474ed1c9 100644 (file)
@@ -461,7 +461,7 @@ extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M,
 
 extern "C" void LLVMRustSetLLVMOptions(int Argc, char **Argv) {
   // Initializing the command-line options more than once is not allowed. So,
-  // check if they've already been initialized.  (This could happen if we're
+  // check if they've already been initialized. (This could happen if we're
   // being called from rustpkg, for example). If the arguments change, then
   // that's just kinda unfortunate.
   static bool Initialized = false;
@@ -1428,7 +1428,7 @@ LLVMRustThinLTOBufferLen(const LLVMRustThinLTOBuffer *Buffer) {
 }
 
 // This is what we used to parse upstream bitcode for actual ThinLTO
-// processing.  We'll call this once per module optimized through ThinLTO, and
+// processing. We'll call this once per module optimized through ThinLTO, and
 // it'll be called concurrently on many threads.
 extern "C" LLVMModuleRef
 LLVMRustParseBitcodeForLTO(LLVMContextRef Context,
index 8f94e8a4ab2e1d2422d009ec6665eeb7e209ab88..87b0e1273eb7761ed06ab0390704af2ae8c2b645 100644 (file)
@@ -1349,18 +1349,16 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
     return LLVMBFloatTypeKind;
   case Type::X86_AMXTyID:
     return LLVMX86_AMXTypeKind;
-#if LLVM_VERSION_GE(15, 0) && LLVM_VERSION_LT(16, 0)
-  case Type::DXILPointerTyID:
-    report_fatal_error("Rust does not support DirectX typed pointers.");
-    break;
-#endif
-#if LLVM_VERSION_GE(16, 0)
-  case Type::TypedPointerTyID:
-    report_fatal_error("Rust does not support typed pointers.");
-    break;
-#endif
+  default:
+    {
+      std::string error;
+      llvm::raw_string_ostream stream(error);
+      stream << "Rust does not support the TypeID: " << unwrap(Ty)->getTypeID()
+             << " for the type: " << *unwrap(Ty);
+      stream.flush();
+      report_fatal_error(error.c_str());
+    }
   }
-  report_fatal_error("Unhandled TypeID.");
 }
 
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef)
index 32338f9dfc5e3893c833eb754769309379b6f1e9..08098c9bb2a85c5a2c37b7a557e7b91fc5f4a2bc 100644 (file)
@@ -4,7 +4,10 @@
 };
 use fluent_bundle::{FluentBundle, FluentError, FluentResource};
 use fluent_syntax::{
-    ast::{Attribute, Entry, Identifier, Message},
+    ast::{
+        Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern,
+        PatternElement,
+    },
     parser::ParserError,
 };
 use proc_macro::{Diagnostic, Level, Span};
@@ -185,9 +188,12 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
         };
 
         let mut constants = TokenStream::new();
+        let mut messagerefs = Vec::new();
         for entry in resource.entries() {
             let span = res.krate.span();
-            if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry {
+            if let Entry::Message(Message { id: Identifier { name }, attributes, value, .. }) =
+                entry
+            {
                 let _ = previous_defns.entry(name.to_string()).or_insert(path_span);
 
                 if name.contains('-') {
@@ -200,6 +206,18 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                     .emit();
                 }
 
+                if let Some(Pattern { elements }) = value {
+                    for elt in elements {
+                        if let PatternElement::Placeable {
+                            expression:
+                                Expression::Inline(InlineExpression::MessageReference { id, .. }),
+                        } = elt
+                        {
+                            messagerefs.push((id.name, *name));
+                        }
+                    }
+                }
+
                 // Require that the message name starts with the crate name
                 // `hir_typeck_foo_bar` (in `hir_typeck.ftl`)
                 // `const_eval_baz` (in `const_eval.ftl`)
@@ -258,6 +276,18 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
             }
         }
 
+        for (mref, name) in messagerefs.into_iter() {
+            if !previous_defns.contains_key(mref) {
+                Diagnostic::spanned(
+                    path_span,
+                    Level::Error,
+                    format!("referenced message `{mref}` does not exist (in message `{name}`)"),
+                )
+                .help(&format!("you may have meant to use a variable reference (`{{${mref}}}`)"))
+                .emit();
+            }
+        }
+
         if let Err(errs) = bundle.add_resource(resource) {
             for e in errs {
                 match e {
index 14e6aa6e0c17baec8b57e251f08a96980c71b11a..1f95661ce9d5f54bb770a764c902a835bec7afe1 100644 (file)
@@ -26,7 +26,7 @@ fn visit_with<__V: ::rustc_middle::ty::visit::TypeVisitor<'tcx>>(
                 __visitor: &mut __V
             ) -> ::std::ops::ControlFlow<__V::BreakTy> {
                 match *self { #body_visit }
-                ::std::ops::ControlFlow::CONTINUE
+                ::std::ops::ControlFlow::Continue(())
             }
         },
     )
index 6d85103c9d1329552f349b687eecaf3fd05db5fc..bee5c8541d68ee9f5f580e80871ef486e9fe74d5 100644 (file)
@@ -6,6 +6,7 @@ edition = "2021"
 [lib]
 
 [dependencies]
+bitflags = "1.2.1"
 libloading = "0.7.1"
 odht = { version = "0.3.1", features = ["nightly"] }
 snap = "1"
index 7601f6bd3221efaae15ef9b76f4c54366cd9628c..f6431899731fffdeea6d97a3170f96e924ba984c 100644 (file)
@@ -90,7 +90,7 @@ enum MetadataKind {
     let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata");
 
     // If the user requests metadata as output, rename `metadata_filename`
-    // to the expected output `out_filename`.  The match above should ensure
+    // to the expected output `out_filename`. The match above should ensure
     // this file always exists.
     let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
     let (metadata_filename, metadata_tmpdir) = if need_metadata_file {
index 92dc5bd41cbab45ae3ac84031c10d63b2f0b01c9..0f5f74007c1060536912477a6b5815635a37a7d1 100644 (file)
@@ -591,7 +591,7 @@ fn extract_one(
                     Err(MetadataError::LoadFailure(err)) => {
                         info!("no metadata found: {}", err);
                         // The file was present and created by the same compiler version, but we
-                        // couldn't load it for some reason.  Give a hard error instead of silently
+                        // couldn't load it for some reason. Give a hard error instead of silently
                         // ignoring it, but only if we would have given an error anyway.
                         self.crate_rejections
                             .via_invalid
index 59869ee417377635ff55a3093aa64ebb3f2779ca..6f05c76e89de1adc89b5e7344f186dd3d565c8c4 100644 (file)
@@ -433,10 +433,10 @@ fn process_command_line(&mut self) {
         }
 
         // Update kind and, optionally, the name of all native libraries
-        // (there may be more than one) with the specified name.  If any
+        // (there may be more than one) with the specified name. If any
         // library is mentioned more than once, keep the latest mention
         // of it, so that any possible dependent libraries appear before
-        // it.  (This ensures that the linker is able to see symbols from
+        // it. (This ensures that the linker is able to see symbols from
         // all possible dependent libraries before linking in the library
         // in question.)
         for passed_lib in &self.tcx.sess.opts.libs {
index 143d8f2f1e18d1fca476640d18af792bcfecf2c1..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) }
@@ -1594,12 +1594,12 @@ fn get_generator_diagnostic_data(
             })
     }
 
-    fn get_may_have_doc_links(self, index: DefIndex) -> bool {
-        self.root.tables.may_have_doc_links.get(self, index).is_some()
+    fn get_attr_flags(self, index: DefIndex) -> AttrFlags {
+        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 cb451931dfe179d51047b73036f80a9f16c14865..9b1401f4a44dfdf922120faf9bd9f165c902d3c9 100644 (file)
@@ -1,6 +1,7 @@
 use crate::creader::{CStore, LoadedMacro};
 use crate::foreign_modules;
 use crate::native_libs;
+use crate::rmeta::AttrFlags;
 
 use rustc_ast as ast;
 use rustc_attr::Deprecation;
@@ -201,6 +202,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
     thir_abstract_const => { table }
     optimized_mir => { table }
     mir_for_ctfe => { table }
+    mir_generator_witnesses => { table }
     promoted_mir => { table }
     def_span => { table }
     def_ident_span => { table }
@@ -223,6 +225,10 @@ fn into_args(self) -> (DefId, SimplifiedType) {
     generator_kind => { table }
     trait_def => { table }
     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)
+    }
     collect_return_position_impl_trait_in_trait_tys => {
         Ok(cdata
             .root
@@ -329,6 +335,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
     crate_extern_paths => { cdata.source().paths().cloned().collect() }
     expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
     generator_diagnostic_data => { cdata.get_generator_diagnostic_data(tcx, def_id.index) }
+    is_doc_hidden => { cdata.get_attr_flags(def_id.index).contains(AttrFlags::IS_DOC_HIDDEN) }
 }
 
 pub(in crate::rmeta) fn provide(providers: &mut Providers) {
@@ -382,7 +389,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
             // keys from the former.
             // This is a rudimentary check that does not catch all cases,
             // just the easiest.
-            let mut fallback_map: DefIdMap<DefId> = Default::default();
+            let mut fallback_map: Vec<(DefId, DefId)> = Default::default();
 
             // Issue 46112: We want the map to prefer the shortest
             // paths when reporting the path to an item. Therefore we
@@ -412,12 +419,12 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
 
                 if let Some(def_id) = child.res.opt_def_id() {
                     if child.ident.name == kw::Underscore {
-                        fallback_map.insert(def_id, parent);
+                        fallback_map.push((def_id, parent));
                         return;
                     }
 
-                    if ty::util::is_doc_hidden(tcx, parent) {
-                        fallback_map.insert(def_id, parent);
+                    if tcx.is_doc_hidden(parent) {
+                        fallback_map.push((def_id, parent));
                         return;
                     }
 
@@ -451,6 +458,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
             // Fill in any missing entries with the less preferable path.
             // If this path re-exports the child as `_`, we still use this
             // path in a diagnostic that suggests importing `::*`.
+
             for (child, parent) in fallback_map {
                 visible_parent_map.entry(child).or_insert(parent);
             }
@@ -621,7 +629,15 @@ pub fn associated_item_def_ids_untracked<'a>(
     }
 
     pub fn may_have_doc_links_untracked(&self, def_id: DefId) -> bool {
-        self.get_crate_data(def_id.krate).get_may_have_doc_links(def_id.index)
+        self.get_crate_data(def_id.krate)
+            .get_attr_flags(def_id.index)
+            .contains(AttrFlags::MAY_HAVE_DOC_LINKS)
+    }
+
+    pub fn is_doc_hidden_untracked(&self, def_id: DefId) -> bool {
+        self.get_crate_data(def_id.krate)
+            .get_attr_flags(def_id.index)
+            .contains(AttrFlags::IS_DOC_HIDDEN)
     }
 }
 
index 030328d1e26ff1f6b64feb983aba60d89a25eb50..29507ff3a86c1dc2f27e66027f67e46ceea53331 100644 (file)
@@ -3,6 +3,7 @@
 use crate::rmeta::table::TableBuilder;
 use crate::rmeta::*;
 
+use rustc_ast::util::comments;
 use rustc_ast::Attribute;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
@@ -38,7 +39,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;
@@ -172,7 +172,7 @@ fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
 impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnId {
     fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
         if self.krate == LOCAL_CRATE {
-            // We will only write details for local expansions.  Non-local expansions will fetch
+            // We will only write details for local expansions. Non-local expansions will fetch
             // data from the corresponding crate's metadata.
             // FIXME(#43047) FIXME(#74731) We may eventually want to avoid relying on external
             // metadata from proc-macro crates.
@@ -483,7 +483,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();
 
@@ -760,36 +760,54 @@ macro_rules! stat {
     }
 }
 
+struct AnalyzeAttrState {
+    is_exported: bool,
+    may_have_doc_links: bool,
+    is_doc_hidden: bool,
+}
+
 /// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and
 /// useful in downstream crates. Local-only attributes are an obvious example, but some
 /// rustdoc-specific attributes can equally be of use while documenting the current crate only.
 ///
 /// Removing these superfluous attributes speeds up compilation by making the metadata smaller.
 ///
-/// Note: the `is_def_id_public` parameter is used to cache whether the given `DefId` has a public
+/// Note: the `is_exported` parameter is used to cache whether the given `DefId` has a public
 /// visibility: this is a piece of data that can be computed once per defid, and not once per
 /// attribute. Some attributes would only be usable downstream if they are public.
 #[inline]
-fn should_encode_attr(
-    tcx: TyCtxt<'_>,
-    attr: &Attribute,
-    def_id: LocalDefId,
-    is_def_id_public: &mut Option<bool>,
-) -> bool {
+fn analyze_attr(attr: &Attribute, state: &mut AnalyzeAttrState) -> bool {
+    let mut should_encode = false;
     if rustc_feature::is_builtin_only_local(attr.name_or_empty()) {
         // Attributes marked local-only don't need to be encoded for downstream crates.
-        false
-    } else if attr.doc_str().is_some() {
-        // We keep all public doc comments because they might be "imported" into downstream crates
-        // if they use `#[doc(inline)]` to copy an item's documentation into their own.
-        *is_def_id_public.get_or_insert_with(|| tcx.effective_visibilities(()).is_exported(def_id))
+    } else if let Some(s) = attr.doc_str() {
+        // We keep all doc comments reachable to rustdoc because they might be "imported" into
+        // downstream crates if they use `#[doc(inline)]` to copy an item's documentation into
+        // their own.
+        if state.is_exported {
+            should_encode = true;
+            if comments::may_have_doc_links(s.as_str()) {
+                state.may_have_doc_links = true;
+            }
+        }
     } else if attr.has_name(sym::doc) {
-        // If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can
-        // remove it. It won't be inlinable in downstream crates.
-        attr.meta_item_list().map(|l| l.iter().any(|l| !l.has_name(sym::inline))).unwrap_or(false)
+        // If this is a `doc` attribute that doesn't have anything except maybe `inline` (as in
+        // `#[doc(inline)]`), then we can remove it. It won't be inlinable in downstream crates.
+        if let Some(item_list) = attr.meta_item_list() {
+            for item in item_list {
+                if !item.has_name(sym::inline) {
+                    should_encode = true;
+                    if item.has_name(sym::hidden) {
+                        state.is_doc_hidden = true;
+                        break;
+                    }
+                }
+            }
+        }
     } else {
-        true
+        should_encode = true;
     }
+    should_encode
 }
 
 fn should_encode_visibility(def_kind: DefKind) -> bool {
@@ -888,8 +906,8 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
         | DefKind::AssocConst
         | DefKind::Static(..)
         | DefKind::Const => (true, false),
-        // Full-fledged functions
-        DefKind::AssocFn | DefKind::Fn => {
+        // Full-fledged functions + closures
+        DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
             let generics = tcx.generics_of(def_id);
             let needs_inline = (generics.requires_monomorphization(tcx)
                 || tcx.codegen_fn_attrs(def_id).requests_inline())
@@ -900,15 +918,6 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
             let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir;
             (is_const_fn, needs_inline || always_encode_mir)
         }
-        // Closures can't be const fn.
-        DefKind::Closure => {
-            let generics = tcx.generics_of(def_id);
-            let needs_inline = (generics.requires_monomorphization(tcx)
-                || tcx.codegen_fn_attrs(def_id).requests_inline())
-                && tcx.sess.opts.output_types.should_codegen();
-            let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir;
-            (false, needs_inline || always_encode_mir)
-        }
         // Generators require optimized MIR to compute layout.
         DefKind::Generator => (false, true),
         // The others don't have MIR.
@@ -1103,7 +1112,7 @@ fn should_encode_trait_impl_trait_tys(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     // of the trait fn to look for any RPITITs, but that's kinda doing a lot
     // of work. We can probably remove this when we refactor RPITITs to be
     // associated types.
-    tcx.fn_sig(trait_item_def_id).skip_binder().output().walk().any(|arg| {
+    tcx.fn_sig(trait_item_def_id).subst_identity().skip_binder().output().walk().any(|arg| {
         if let ty::GenericArgKind::Type(ty) = arg.unpack()
             && let ty::Alias(ty::Projection, data) = ty.kind()
             && tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder
@@ -1118,17 +1127,28 @@ fn should_encode_trait_impl_trait_tys(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     fn encode_attrs(&mut self, def_id: LocalDefId) {
         let tcx = self.tcx;
-        let mut is_public: Option<bool> = None;
-
-        let mut attrs = tcx
+        let mut state = AnalyzeAttrState {
+            is_exported: tcx.effective_visibilities(()).is_exported(def_id),
+            may_have_doc_links: false,
+            is_doc_hidden: false,
+        };
+        let attr_iter = tcx
             .hir()
             .attrs(tcx.hir().local_def_id_to_hir_id(def_id))
             .iter()
-            .filter(move |attr| should_encode_attr(tcx, attr, def_id, &mut is_public));
+            .filter(|attr| analyze_attr(attr, &mut state));
+
+        record_array!(self.tables.attributes[def_id.to_def_id()] <- attr_iter);
 
-        record_array!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone());
-        if attrs.any(|attr| attr.may_have_doc_links()) {
-            self.tables.may_have_doc_links.set(def_id.local_def_index, ());
+        let mut attr_flags = AttrFlags::empty();
+        if state.may_have_doc_links {
+            attr_flags |= AttrFlags::MAY_HAVE_DOC_LINKS;
+        }
+        if state.is_doc_hidden {
+            attr_flags |= AttrFlags::IS_DOC_HIDDEN;
+        }
+        if !attr_flags.is_empty() {
+            self.tables.attr_flags.set_nullable(def_id.local_def_index, attr_flags);
         }
     }
 
@@ -1187,8 +1207,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)
@@ -1196,8 +1215,11 @@ fn encode_def_ids(&mut self) {
                 record!(self.tables.trait_impl_trait_tys[def_id] <- table);
             }
         }
-        let inherent_impls = tcx.crate_inherent_impls(());
-        for (def_id, implementations) in inherent_impls.inherent_impls.iter() {
+        let inherent_impls = tcx.with_stable_hashing_context(|hcx| {
+            tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true)
+        });
+
+        for (def_id, implementations) in inherent_impls {
             if implementations.is_empty() {
                 continue;
             }
@@ -1208,46 +1230,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);
+            }
         }
     }
 
@@ -1281,8 +1310,8 @@ fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) {
                         hir::ItemKind::Struct(ref vdata, _) => {
                             yield item_id.owner_id.def_id.local_def_index;
                             // Encode constructors which take a separate slot in value namespace.
-                            if let Some(ctor_hir_id) = vdata.ctor_hir_id() {
-                                yield tcx.hir().local_def_id(ctor_hir_id).local_def_index;
+                            if let Some(ctor_def_id) = vdata.ctor_def_id() {
+                                yield ctor_def_id.local_def_index;
                             }
                         }
                         _ if tcx.def_key(item_id.owner_id.to_def_id()).get_opt_name().is_some() => {
@@ -1300,25 +1329,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);
@@ -1382,7 +1392,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);
             }
         }
     }
@@ -1404,6 +1414,10 @@ fn encode_mir(&mut self) {
             debug!("EntryBuilder::encode_mir({:?})", def_id);
             if encode_opt {
                 record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id));
+
+                if let DefKind::Generator = self.tcx.def_kind(def_id) && tcx.sess.opts.unstable_opts.drop_tracking_mir {
+                    record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- tcx.mir_generator_witnesses(def_id));
+                }
             }
             if encode_const {
                 record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id));
@@ -1514,48 +1528,24 @@ 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);
             }
             hir::ItemKind::Mod(ref m) => {
                 return self.encode_info_for_mod(item.owner_id.def_id, m);
             }
-            hir::ItemKind::OpaqueTy(..) => {
+            hir::ItemKind::OpaqueTy(ref opaque) => {
                 self.encode_explicit_item_bounds(def_id);
-            }
-            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(),
-                });
+                if matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) {
+                    self.tables.is_type_alias_impl_trait.set_nullable(def_id.index, true);
+                }
             }
             hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
                 self.tables.impl_defaultness.set(def_id.index, *defaultness);
                 self.tables.constness.set(def_id.index, *constness);
 
-                let trait_ref = self.tcx.impl_trait_ref(def_id);
+                let trait_ref = self.tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::skip_binder);
                 if let Some(trait_ref) = trait_ref {
                     let trait_def = self.tcx.trait_def(trait_ref.def_id);
                     if let Ok(mut an) = trait_def.ancestors(self.tcx, def_id) {
@@ -1589,31 +1579,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] <-
@@ -1628,7 +1602,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 {
@@ -1641,17 +1615,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()
@@ -1688,7 +1651,7 @@ fn encode_info_for_closure(&mut self, def_id: LocalDefId) {
             ty::Closure(_, substs) => {
                 let constness = self.tcx.constness(def_id.to_def_id());
                 self.tables.constness.set(def_id.to_def_id().index, constness);
-                record!(self.tables.fn_sig[def_id.to_def_id()] <- substs.as_closure().sig());
+                record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder(substs.as_closure().sig()));
             }
 
             _ => bug!("closure that is neither generator nor closure"),
@@ -1899,6 +1862,8 @@ fn encode_impls(&mut self) -> LazyArray<TraitImpls> {
         for id in tcx.hir().items() {
             if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
                 if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) {
+                    let trait_ref = trait_ref.subst_identity();
+
                     let simplified_self_ty = fast_reject::simplify_type(
                         self.tcx,
                         trait_ref.self_ty(),
@@ -2028,7 +1993,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 bf9be714daf7e940b09c29bdc1819efee06106a6..37af9e64e9a3da5002ee527d5b6f655d05366506 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>>,
@@ -357,20 +369,20 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     super_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
     type_of: Table<DefIndex, LazyValue<Ty<'static>>>,
     variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
-    fn_sig: Table<DefIndex, LazyValue<ty::PolyFnSig<'static>>>,
+    fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::PolyFnSig<'static>>>>,
     codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
-    impl_trait_ref: Table<DefIndex, LazyValue<ty::TraitRef<'static>>>,
-    const_param_default: Table<DefIndex, LazyValue<rustc_middle::ty::Const<'static>>>,
+    impl_trait_ref: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::TraitRef<'static>>>>,
+    const_param_default: Table<DefIndex, LazyValue<ty::EarlyBinder<rustc_middle::ty::Const<'static>>>>,
     object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
     optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
     mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
+    mir_generator_witnesses: Table<DefIndex, LazyValue<mir::GeneratorLayout<'static>>>,
     promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>,
     // FIXME(compiler-errors): Why isn't this a LazyArray?
     thir_abstract_const: Table<DefIndex, LazyValue<ty::Const<'static>>>,
     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 +392,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,16 +406,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>>>,
-    may_have_doc_links: Table<DefIndex, ()>,
     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>>,
-
     trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, Ty<'static>>>>,
 }
 
@@ -416,6 +423,14 @@ struct VariantData {
     is_non_exhaustive: bool,
 }
 
+bitflags::bitflags! {
+    #[derive(Default)]
+    pub struct AttrFlags: u8 {
+        const MAY_HAVE_DOC_LINKS = 1 << 0;
+        const IS_DOC_HIDDEN      = 1 << 1;
+    }
+}
+
 // Tags used for encoding Spans:
 const TAG_VALID_SPAN_LOCAL: u8 = 0;
 const TAG_VALID_SPAN_FOREIGN: u8 = 1;
@@ -438,4 +453,5 @@ pub fn provide(providers: &mut Providers) {
     IncoherentImpls,
     CrateRoot,
     CrateDep,
+    AttrFlags,
 }
index 716655c7f144d7de62e0d5c1bc64ee9a703c5b55..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,17 +200,31 @@ impl FixedSizeEncoding for Option<RawDefId> {
     }
 }
 
-impl FixedSizeEncoding for Option<()> {
+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])
     }
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 1]) {
-        b[0] = self.is_some() as u8
+        b[0] = self.bits();
+    }
+}
+
+impl FixedSizeEncoding for bool {
+    type ByteArray = [u8; 1];
+
+    #[inline]
+    fn from_bytes(b: &[u8; 1]) -> Self {
+        b[0] != 0
+    }
+
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 1]) {
+        b[0] = self as u8
     }
 }
 
@@ -259,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);
@@ -309,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 f816d614500a07b9322ae679745de27cb097fc98..72f4f6e649bcf178e51017fc2fb8a57bb81b52a0 100644 (file)
@@ -105,7 +105,7 @@ macro_rules! arena_types {
             // (during lowering) and the `librustc_middle` arena (for decoding MIR)
             [decode] asm_template: rustc_ast::InlineAsmTemplatePiece,
             [decode] used_trait_imports: rustc_data_structures::unord::UnordSet<rustc_hir::def_id::LocalDefId>,
-            [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::def_id::LocalDefId>,
+            [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::ItemLocalId>,
             [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
 
             [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>,
index 48bae7a2d4e1ff2a6a5ebdb36f082657fbe44718..5bd6b0704426b667b4e0435cd4ac3bb30f5f66a8 100644 (file)
 use rustc_target::spec::abi::Abi;
 
 #[inline]
-pub fn associated_body(node: Node<'_>) -> Option<BodyId> {
+pub fn associated_body(node: Node<'_>) -> Option<(LocalDefId, BodyId)> {
     match node {
         Node::Item(Item {
+            owner_id,
             kind: ItemKind::Const(_, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body),
             ..
         })
         | Node::TraitItem(TraitItem {
+            owner_id,
             kind:
                 TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)),
             ..
         })
         | Node::ImplItem(ImplItem {
+            owner_id,
             kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body),
             ..
-        })
-        | Node::Expr(Expr { kind: ExprKind::Closure(Closure { body, .. }), .. }) => Some(*body),
+        }) => Some((owner_id.def_id, *body)),
+
+        Node::Expr(Expr { kind: ExprKind::Closure(Closure { def_id, body, .. }), .. }) => {
+            Some((*def_id, *body))
+        }
 
-        Node::AnonConst(constant) => Some(constant.body),
+        Node::AnonConst(constant) => Some((constant.def_id, constant.body)),
 
         _ => None,
     }
@@ -43,7 +49,7 @@ pub fn associated_body(node: Node<'_>) -> Option<BodyId> {
 
 fn is_body_owner(node: Node<'_>, hir_id: HirId) -> bool {
     match associated_body(node) {
-        Some(b) => b.hir_id == hir_id,
+        Some((_, b)) => b.hir_id == hir_id,
         None => false,
     }
 }
@@ -154,10 +160,6 @@ pub fn def_key(self, def_id: LocalDefId) -> DefKey {
         self.tcx.definitions_untracked().def_key(def_id)
     }
 
-    pub fn def_path_from_hir_id(self, id: HirId) -> Option<DefPath> {
-        self.opt_local_def_id(id).map(|def_id| self.def_path(def_id))
-    }
-
     pub fn def_path(self, def_id: LocalDefId) -> DefPath {
         // Accessing the DefPath is ok, since it is part of DefPathHash.
         self.tcx.definitions_untracked().def_path(def_id)
@@ -169,32 +171,6 @@ pub fn def_path_hash(self, def_id: LocalDefId) -> DefPathHash {
         self.tcx.definitions_untracked().def_path_hash(def_id)
     }
 
-    #[inline]
-    #[track_caller]
-    pub fn local_def_id(self, hir_id: HirId) -> LocalDefId {
-        self.opt_local_def_id(hir_id).unwrap_or_else(|| {
-            bug!(
-                "local_def_id: no entry for `{:?}`, which has a map of `{:?}`",
-                hir_id,
-                self.find(hir_id)
-            )
-        })
-    }
-
-    #[inline]
-    pub fn opt_local_def_id(self, hir_id: HirId) -> Option<LocalDefId> {
-        if hir_id.local_id == ItemLocalId::new(0) {
-            Some(hir_id.owner.def_id)
-        } else {
-            self.tcx
-                .hir_owner_nodes(hir_id.owner)
-                .as_owner()?
-                .local_id_to_def_id
-                .get(&hir_id.local_id)
-                .copied()
-        }
-    }
-
     #[inline]
     pub fn local_def_id_to_hir_id(self, def_id: LocalDefId) -> HirId {
         self.tcx.local_def_id_to_hir_id(def_id)
@@ -410,8 +386,8 @@ pub fn fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> {
     #[track_caller]
     pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId {
         for (_, node) in self.parent_iter(hir_id) {
-            if let Some(body) = associated_body(node) {
-                return self.body_owner_def_id(body);
+            if let Some((def_id, _)) = associated_body(node) {
+                return def_id;
             }
         }
 
@@ -427,14 +403,17 @@ pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId {
         parent
     }
 
-    pub fn body_owner_def_id(self, id: BodyId) -> LocalDefId {
-        self.local_def_id(self.body_owner(id))
+    pub fn body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId {
+        let parent = self.parent_id(hir_id);
+        associated_body(self.get(parent)).unwrap().0
     }
 
     /// Given a `LocalDefId`, returns the `BodyId` associated with it,
     /// if the node is a body owner, otherwise returns `None`.
     pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<BodyId> {
-        self.find_by_def_id(id).and_then(associated_body)
+        let node = self.find_by_def_id(id)?;
+        let (_, body_id) = associated_body(node)?;
+        Some(body_id)
     }
 
     /// Given a body owner's id, returns the `BodyId` associated with it.
@@ -582,10 +561,10 @@ pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) {
 
     /// Visits all item-likes in the crate in some deterministic (but unspecified) order. If you
     /// need to process every item-like, and don't care about visiting nested items in a particular
-    /// order then this method is the best choice.  If you do care about this nesting, you should
+    /// order then this method is the best choice. If you do care about this nesting, you should
     /// use the `tcx.hir().walk_toplevel_module`.
     ///
-    /// Note that this function will access HIR for all the item-likes in the crate.  If you only
+    /// Note that this function will access HIR for all the item-likes in the crate. If you only
     /// need to access some of them, it is usually better to manually loop on the iterators
     /// provided by `tcx.hir_crate_items(())`.
     ///
index a633201e3d9ae82091808f6684ebee834eb5434a..dedc65f4cbf45b27352e5b395d30a3c5f88a3c7d 100644 (file)
@@ -36,7 +36,7 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
 }
 
 /// Gather the LocalDefId for each item-like within a module, including items contained within
-/// bodies.  The Ids are in visitor order.  This is used to partition a pass between modules.
+/// bodies. The Ids are in visitor order. This is used to partition a pass between modules.
 #[derive(Debug, HashStable, Encodable, Decodable)]
 pub struct ModuleItems {
     submodules: Box<[OwnerId]>,
@@ -102,6 +102,7 @@ pub fn parent_module(self, id: HirId) -> LocalDefId {
 
     pub fn impl_subject(self, def_id: DefId) -> ImplSubject<'tcx> {
         self.impl_trait_ref(def_id)
+            .map(|t| t.subst_identity())
             .map(ImplSubject::Trait)
             .unwrap_or_else(|| ImplSubject::Inherent(self.type_of(def_id)))
     }
index 614cf1a0051da8b423c96e536cb018646518ab97..6e130bbf7d8284403fccb3af90c7e1a229a08c86 100644 (file)
 use crate::mir::ConstraintCategory;
 use crate::ty::subst::GenericArg;
 use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
-use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use smallvec::SmallVec;
-use std::iter;
 use std::ops::Index;
 
 /// A "canonicalized" type `V` is one where all free inference
@@ -62,10 +60,26 @@ fn try_fold_with<F: ty::FallibleTypeFolder<'tcx>>(
 /// vectors with the original values that were replaced by canonical
 /// variables. You will need to supply it later to instantiate the
 /// canonicalized query response.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
 #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct CanonicalVarValues<'tcx> {
-    pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>,
+    pub var_values: ty::SubstsRef<'tcx>,
+}
+
+impl CanonicalVarValues<'_> {
+    pub fn is_identity(&self) -> bool {
+        self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() {
+            ty::GenericArgKind::Lifetime(r) => {
+                matches!(*r, ty::ReLateBound(ty::INNERMOST, br) if br.var.as_usize() == bv)
+            }
+            ty::GenericArgKind::Type(ty) => {
+                matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv)
+            }
+            ty::GenericArgKind::Const(ct) => {
+                matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv)
+            }
+        })
+    }
 }
 
 /// When we canonicalize a value to form a query, we wind up replacing
@@ -323,51 +337,57 @@ pub fn unchecked_rebind<W>(self, value: W) -> Canonical<'tcx, W> {
 }
 
 impl<'tcx> CanonicalVarValues<'tcx> {
-    #[inline]
-    pub fn len(&self) -> usize {
-        self.var_values.len()
-    }
-
-    /// Makes an identity substitution from this one: each bound var
-    /// is matched to the same bound var, preserving the original kinds.
-    /// For example, if we have:
-    /// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]`
-    /// we'll return a substitution `subst` with:
-    /// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`.
-    pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self {
-        use crate::ty::subst::GenericArgKind;
-
+    // Given a list of canonical variables, construct a set of values which are
+    // the identity response.
+    pub fn make_identity(
+        tcx: TyCtxt<'tcx>,
+        infos: CanonicalVarInfos<'tcx>,
+    ) -> CanonicalVarValues<'tcx> {
         CanonicalVarValues {
-            var_values: iter::zip(&self.var_values, 0..)
-                .map(|(kind, i)| match kind.unpack() {
-                    GenericArgKind::Type(..) => {
-                        tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
-                    }
-                    GenericArgKind::Lifetime(..) => {
-                        let br = ty::BoundRegion {
-                            var: ty::BoundVar::from_u32(i),
-                            kind: ty::BrAnon(i, None),
-                        };
-                        tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
+            var_values: tcx.mk_substs(infos.iter().enumerate().map(
+                |(i, info)| -> ty::GenericArg<'tcx> {
+                    match info.kind {
+                        CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => tcx
+                            .mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into()))
+                            .into(),
+                        CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
+                            let br = ty::BoundRegion {
+                                var: ty::BoundVar::from_usize(i),
+                                kind: ty::BrAnon(i as u32, None),
+                            };
+                            tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
+                        }
+                        CanonicalVarKind::Const(_, ty)
+                        | CanonicalVarKind::PlaceholderConst(_, ty) => tcx
+                            .mk_const(
+                                ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)),
+                                ty,
+                            )
+                            .into(),
                     }
-                    GenericArgKind::Const(ct) => tcx
-                        .mk_const(
-                            ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
-                            ct.ty(),
-                        )
-                        .into(),
-                })
-                .collect(),
+                },
+            )),
         }
     }
+
+    /// Creates dummy var values which should not be used in a
+    /// canonical response.
+    pub fn dummy() -> CanonicalVarValues<'tcx> {
+        CanonicalVarValues { var_values: ty::List::empty() }
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.var_values.len()
+    }
 }
 
 impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
     type Item = GenericArg<'tcx>;
-    type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>;
+    type IntoIter = ::std::iter::Copied<::std::slice::Iter<'a, GenericArg<'tcx>>>;
 
     fn into_iter(self) -> Self::IntoIter {
-        self.var_values.iter().cloned()
+        self.var_values.iter()
     }
 }
 
@@ -375,6 +395,6 @@ impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
     type Output = GenericArg<'tcx>;
 
     fn index(&self, value: BoundVar) -> &GenericArg<'tcx> {
-        &self.var_values[value]
+        &self.var_values[value.as_usize()]
     }
 }
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 5ca4d260179ceff29f982033a0a3cb4e171e089d..250f3d0797eb52cdb2c503ab914967d26235a956 100644 (file)
@@ -93,7 +93,7 @@ fn visit_with<F: $crate::ty::visit::TypeVisitor<$tcx>>(
                     _: &mut F)
                     -> ::std::ops::ControlFlow<F::BreakTy>
                 {
-                    ::std::ops::ControlFlow::CONTINUE
+                    ::std::ops::ControlFlow::Continue(())
                 }
             }
         )+
@@ -219,7 +219,7 @@ fn visit_with<V: $crate::ty::visit::TypeVisitor<$tcx>>(
                         $($crate::ty::visit::TypeVisitable::visit_with(
                             $variant_arg, $visitor
                         )?;)*
-                        ::std::ops::ControlFlow::CONTINUE
+                        ::std::ops::ControlFlow::Continue(())
                     }
                     $($output)*
                 )
@@ -237,7 +237,7 @@ fn visit_with<V: $crate::ty::visit::TypeVisitor<$tcx>>(
                         $($crate::ty::visit::TypeVisitable::visit_with(
                             $variant_arg, $visitor
                         )?;)*
-                        ::std::ops::ControlFlow::CONTINUE
+                        ::std::ops::ControlFlow::Continue(())
                     }
                     $($output)*
                 )
@@ -251,7 +251,7 @@ fn visit_with<V: $crate::ty::visit::TypeVisitor<$tcx>>(
             @VisitVariants($this, $visitor)
                 input($($input)*)
                 output(
-                    $variant => { ::std::ops::ControlFlow::CONTINUE }
+                    $variant => { ::std::ops::ControlFlow::Continue(()) }
                     $($output)*
                 )
         )
index 752cbdeae6b25df2eb76ad53c4db05c3edbfb534..b93871769b791c9ab7de6f3c0aa605d3cef4f89b 100644 (file)
@@ -1,41 +1,46 @@
-use crate::mir::graph_cyclic_cache::GraphIsCyclicCache;
-use crate::mir::predecessors::{PredecessorCache, Predecessors};
-use crate::mir::switch_sources::{SwitchSourceCache, SwitchSources};
-use crate::mir::traversal::PostorderCache;
-use crate::mir::{BasicBlock, BasicBlockData, Successors, START_BLOCK};
+use crate::mir::traversal::Postorder;
+use crate::mir::{BasicBlock, BasicBlockData, Successors, Terminator, TerminatorKind, START_BLOCK};
 
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::graph;
 use rustc_data_structures::graph::dominators::{dominators, Dominators};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::OnceCell;
 use rustc_index::vec::IndexVec;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use smallvec::SmallVec;
 
 #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct BasicBlocks<'tcx> {
     basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
-    predecessor_cache: PredecessorCache,
-    switch_source_cache: SwitchSourceCache,
-    is_cyclic: GraphIsCyclicCache,
-    postorder_cache: PostorderCache,
+    cache: Cache,
+}
+
+// Typically 95%+ of basic blocks have 4 or fewer predecessors.
+pub type Predecessors = IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>;
+
+pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option<u128>; 1]>>;
+
+#[derive(Clone, Default, Debug)]
+struct Cache {
+    predecessors: OnceCell<Predecessors>,
+    switch_sources: OnceCell<SwitchSources>,
+    is_cyclic: OnceCell<bool>,
+    postorder: OnceCell<Vec<BasicBlock>>,
 }
 
 impl<'tcx> BasicBlocks<'tcx> {
     #[inline]
     pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
-        BasicBlocks {
-            basic_blocks,
-            predecessor_cache: PredecessorCache::new(),
-            switch_source_cache: SwitchSourceCache::new(),
-            is_cyclic: GraphIsCyclicCache::new(),
-            postorder_cache: PostorderCache::new(),
-        }
+        BasicBlocks { basic_blocks, cache: Cache::default() }
     }
 
     /// Returns true if control-flow graph contains a cycle reachable from the `START_BLOCK`.
     #[inline]
     pub fn is_cfg_cyclic(&self) -> bool {
-        self.is_cyclic.is_cyclic(self)
+        *self.cache.is_cyclic.get_or_init(|| graph::is_cyclic(self))
     }
 
-    #[inline]
     pub fn dominators(&self) -> Dominators<BasicBlock> {
         dominators(&self)
     }
@@ -43,20 +48,46 @@ pub fn dominators(&self) -> Dominators<BasicBlock> {
     /// Returns predecessors for each basic block.
     #[inline]
     pub fn predecessors(&self) -> &Predecessors {
-        self.predecessor_cache.compute(&self.basic_blocks)
+        self.cache.predecessors.get_or_init(|| {
+            let mut preds = IndexVec::from_elem(SmallVec::new(), &self.basic_blocks);
+            for (bb, data) in self.basic_blocks.iter_enumerated() {
+                if let Some(term) = &data.terminator {
+                    for succ in term.successors() {
+                        preds[succ].push(bb);
+                    }
+                }
+            }
+            preds
+        })
     }
 
     /// Returns basic blocks in a postorder.
     #[inline]
     pub fn postorder(&self) -> &[BasicBlock] {
-        self.postorder_cache.compute(&self.basic_blocks)
+        self.cache.postorder.get_or_init(|| {
+            Postorder::new(&self.basic_blocks, START_BLOCK).map(|(bb, _)| bb).collect()
+        })
     }
 
     /// `switch_sources()[&(target, switch)]` returns a list of switch
     /// values that lead to a `target` block from a `switch` block.
     #[inline]
     pub fn switch_sources(&self) -> &SwitchSources {
-        self.switch_source_cache.compute(&self.basic_blocks)
+        self.cache.switch_sources.get_or_init(|| {
+            let mut switch_sources: SwitchSources = FxHashMap::default();
+            for (bb, data) in self.basic_blocks.iter_enumerated() {
+                if let Some(Terminator {
+                    kind: TerminatorKind::SwitchInt { targets, .. }, ..
+                }) = &data.terminator
+                {
+                    for (value, target) in targets.iter() {
+                        switch_sources.entry((target, bb)).or_default().push(Some(value));
+                    }
+                    switch_sources.entry((targets.otherwise(), bb)).or_default().push(None);
+                }
+            }
+            switch_sources
+        })
     }
 
     /// Returns mutable reference to basic blocks. Invalidates CFG cache.
@@ -88,10 +119,7 @@ pub fn as_mut_preserves_cfg(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockDa
     /// All other methods that allow you to mutate the basic blocks also call this method
     /// themselves, thereby avoiding any risk of accidentally cache invalidation.
     pub fn invalidate_cfg_cache(&mut self) {
-        self.predecessor_cache.invalidate();
-        self.switch_source_cache.invalidate();
-        self.is_cyclic.invalidate();
-        self.postorder_cache.invalidate();
+        self.cache = Cache::default();
     }
 }
 
@@ -145,3 +173,24 @@ fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_
         self.predecessors()[node].iter().copied()
     }
 }
+
+TrivialTypeTraversalAndLiftImpls! {
+    Cache,
+}
+
+impl<S: Encoder> Encodable<S> for Cache {
+    #[inline]
+    fn encode(&self, _s: &mut S) {}
+}
+
+impl<D: Decoder> Decodable<D> for Cache {
+    #[inline]
+    fn decode(_: &mut D) -> Self {
+        Default::default()
+    }
+}
+
+impl<CTX> HashStable<CTX> for Cache {
+    #[inline]
+    fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {}
+}
diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
deleted file mode 100644 (file)
index f97bf28..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-use rustc_data_structures::graph::{
-    self, DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors,
-};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::OnceCell;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-
-/// Helper type to cache the result of `graph::is_cyclic`.
-#[derive(Clone, Debug)]
-pub(super) struct GraphIsCyclicCache {
-    cache: OnceCell<bool>,
-}
-
-impl GraphIsCyclicCache {
-    #[inline]
-    pub(super) fn new() -> Self {
-        GraphIsCyclicCache { cache: OnceCell::new() }
-    }
-
-    pub(super) fn is_cyclic<G>(&self, graph: &G) -> bool
-    where
-        G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes,
-    {
-        *self.cache.get_or_init(|| graph::is_cyclic(graph))
-    }
-
-    /// Invalidates the cache.
-    #[inline]
-    pub(super) fn invalidate(&mut self) {
-        // Invalidating the cache requires mutating the MIR, which in turn requires a unique
-        // reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all
-        // callers of `invalidate` have a unique reference to the MIR and thus to the
-        // cache. This means we never need to do synchronization when `invalidate` is called,
-        // we can simply reinitialize the `OnceCell`.
-        self.cache = OnceCell::new();
-    }
-}
-
-impl<S: Encoder> Encodable<S> for GraphIsCyclicCache {
-    #[inline]
-    fn encode(&self, s: &mut S) {
-        Encodable::encode(&(), s);
-    }
-}
-
-impl<D: Decoder> Decodable<D> for GraphIsCyclicCache {
-    #[inline]
-    fn decode(d: &mut D) -> Self {
-        let () = Decodable::decode(d);
-        Self::new()
-    }
-}
-
-impl<CTX> HashStable<CTX> for GraphIsCyclicCache {
-    #[inline]
-    fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
-        // do nothing
-    }
-}
-
-TrivialTypeTraversalAndLiftImpls! {
-    GraphIsCyclicCache,
-}
index 8fe349d9640dafd776814d0feb5f9b8175a7e92f..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> {
@@ -509,7 +520,7 @@ pub fn create_static_alloc(self, static_id: DefId) -> AllocId {
         self.reserve_and_set_dedup(GlobalAlloc::Static(static_id))
     }
 
-    /// Generates an `AllocId` for a function.  Depending on the function type,
+    /// Generates an `AllocId` for a function. Depending on the function type,
     /// this might get deduplicated or assigned a new ID each time.
     pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
         // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
@@ -518,7 +529,7 @@ pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
         // We thus generate a new `AllocId` for every mention of a function. This means that
         // `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true.
         // However, formatting code relies on function identity (see #58320), so we only do
-        // this for generic functions.  Lifetime parameters are ignored.
+        // this for generic functions. Lifetime parameters are ignored.
         let is_generic = instance
             .substs
             .into_iter()
@@ -535,7 +546,7 @@ pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
         }
     }
 
-    /// Generates an `AllocId` for a (symbolic, not-reified) vtable.  Will get deduplicated.
+    /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated.
     pub fn create_vtable_alloc(
         self,
         ty: Ty<'tcx>,
index 14bdff4568f5e65f8e1fd4c6355bdaf89a4ae4d2..552af589bec59b12f3b2f40516f7ef7f6dce5b37 100644 (file)
 pub mod coverage;
 mod generic_graph;
 pub mod generic_graphviz;
-mod graph_cyclic_cache;
 pub mod graphviz;
 pub mod interpret;
 pub mod mono;
 pub mod patch;
-mod predecessors;
 pub mod pretty;
 mod query;
 pub mod spanview;
 mod syntax;
 pub use syntax::*;
-mod switch_sources;
 pub mod tcx;
 pub mod terminator;
 pub use terminator::*;
@@ -905,6 +902,8 @@ pub enum LocalInfo<'tcx> {
     AggregateTemp,
     /// A temporary created during the pass `Derefer` to avoid it's retagging
     DerefTemp,
+    /// A temporary created for borrow checking.
+    FakeBorrow,
 }
 
 impl<'tcx> LocalDecl<'tcx> {
@@ -1464,6 +1463,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
             }
             Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind),
             Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
+            ConstEvalCounter => write!(fmt, "ConstEvalCounter"),
             Nop => write!(fmt, "nop"),
         }
     }
@@ -2483,7 +2483,7 @@ fn from_opt_const_arg_anon_const(
 
         // FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
         // does not provide the parents generics to anonymous constants. We still allow generic const
-        // parameters by themselves however, e.g. `N`.  These constants would cause an ICE if we were to
+        // parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to
         // ever try to substitute the generic parameters in their bodies.
         //
         // While this doesn't happen as these constants are always used as `ty::ConstKind::Param`, it does
@@ -2507,7 +2507,7 @@ fn from_opt_const_arg_anon_const(
 
         let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
         let parent_substs = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id) {
-            if let Some(parent_did) = tcx.hir().opt_local_def_id(parent_hir_id) {
+            if let Some(parent_did) = parent_hir_id.as_owner() {
                 InternalSubsts::identity_for_item(tcx, parent_did.to_def_id())
             } else {
                 tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter())
@@ -3049,7 +3049,7 @@ pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) ->
         if self.block == other.block {
             self.statement_index <= other.statement_index
         } else {
-            dominators.is_dominated_by(other.block, self.block)
+            dominators.dominates(self.block, other.block)
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs
deleted file mode 100644 (file)
index 5f1fada..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-//! Lazily compute the reverse control-flow graph for the MIR.
-
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::OnceCell;
-use rustc_index::vec::IndexVec;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-use smallvec::SmallVec;
-
-use crate::mir::{BasicBlock, BasicBlockData};
-
-// Typically 95%+ of basic blocks have 4 or fewer predecessors.
-pub type Predecessors = IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>;
-
-#[derive(Clone, Debug)]
-pub(super) struct PredecessorCache {
-    cache: OnceCell<Predecessors>,
-}
-
-impl PredecessorCache {
-    #[inline]
-    pub(super) fn new() -> Self {
-        PredecessorCache { cache: OnceCell::new() }
-    }
-
-    /// Invalidates the predecessor cache.
-    #[inline]
-    pub(super) fn invalidate(&mut self) {
-        // Invalidating the predecessor cache requires mutating the MIR, which in turn requires a
-        // unique reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all
-        // callers of `invalidate` have a unique reference to the MIR and thus to the predecessor
-        // cache. This means we never need to do synchronization when `invalidate` is called, we can
-        // simply reinitialize the `OnceCell`.
-        self.cache = OnceCell::new();
-    }
-
-    /// Returns the predecessor graph for this MIR.
-    #[inline]
-    pub(super) fn compute(
-        &self,
-        basic_blocks: &IndexVec<BasicBlock, BasicBlockData<'_>>,
-    ) -> &Predecessors {
-        self.cache.get_or_init(|| {
-            let mut preds = IndexVec::from_elem(SmallVec::new(), basic_blocks);
-            for (bb, data) in basic_blocks.iter_enumerated() {
-                if let Some(term) = &data.terminator {
-                    for succ in term.successors() {
-                        preds[succ].push(bb);
-                    }
-                }
-            }
-
-            preds
-        })
-    }
-}
-
-impl<S: Encoder> Encodable<S> for PredecessorCache {
-    #[inline]
-    fn encode(&self, _s: &mut S) {}
-}
-
-impl<D: Decoder> Decodable<D> for PredecessorCache {
-    #[inline]
-    fn decode(_: &mut D) -> Self {
-        Self::new()
-    }
-}
-
-impl<CTX> HashStable<CTX> for PredecessorCache {
-    #[inline]
-    fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
-        // do nothing
-    }
-}
-
-TrivialTypeTraversalAndLiftImpls! {
-    PredecessorCache,
-}
index a8a4532223c2d901a47e1cf1f18cb21a718538e7..6155f2bb56ce93bdb0f4c72fa6189e53359254f7 100644 (file)
@@ -135,11 +135,20 @@ pub struct UnsafetyCheckResult {
     pub struct GeneratorSavedLocal {}
 }
 
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+pub struct GeneratorSavedTy<'tcx> {
+    pub ty: Ty<'tcx>,
+    /// Source info corresponding to the local in the original MIR body.
+    pub source_info: SourceInfo,
+    /// Whether the local should be ignored for trait bound computations.
+    pub ignore_for_traits: bool,
+}
+
 /// The layout of generator state.
 #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct GeneratorLayout<'tcx> {
     /// The type of every local stored inside the generator.
-    pub field_tys: IndexVec<GeneratorSavedLocal, Ty<'tcx>>,
+    pub field_tys: IndexVec<GeneratorSavedLocal, GeneratorSavedTy<'tcx>>,
 
     /// Which of the above fields are in each variant. Note that one field may
     /// be stored in multiple variants.
index 887ee57157540e6f408de841d5825761978af356..1610ae1ce1480937d3b6fc1e8b155b6f4480f871 100644 (file)
@@ -250,6 +250,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
         AscribeUserType(..) => "AscribeUserType",
         Coverage(..) => "Coverage",
         Intrinsic(..) => "Intrinsic",
+        ConstEvalCounter => "ConstEvalCounter",
         Nop => "Nop",
     }
 }
@@ -670,7 +671,7 @@ fn fn_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span {
 
 fn hir_body(tcx: TyCtxt<'_>, def_id: DefId) -> Option<&rustc_hir::Body<'_>> {
     let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
-    hir::map::associated_body(hir_node).map(|fn_body_id| tcx.hir().body(fn_body_id))
+    hir::map::associated_body(hir_node).map(|(_, fn_body_id)| tcx.hir().body(fn_body_id))
 }
 
 fn escape_html(s: &str) -> String {
diff --git a/compiler/rustc_middle/src/mir/switch_sources.rs b/compiler/rustc_middle/src/mir/switch_sources.rs
deleted file mode 100644 (file)
index b91c0c2..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-//! Lazily compute the inverse of each `SwitchInt`'s switch targets. Modeled after
-//! `Predecessors`/`PredecessorCache`.
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::OnceCell;
-use rustc_index::vec::IndexVec;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-use smallvec::SmallVec;
-
-use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind};
-
-pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option<u128>; 1]>>;
-
-#[derive(Clone, Debug)]
-pub(super) struct SwitchSourceCache {
-    cache: OnceCell<SwitchSources>,
-}
-
-impl SwitchSourceCache {
-    #[inline]
-    pub(super) fn new() -> Self {
-        SwitchSourceCache { cache: OnceCell::new() }
-    }
-
-    /// Invalidates the switch source cache.
-    #[inline]
-    pub(super) fn invalidate(&mut self) {
-        self.cache = OnceCell::new();
-    }
-
-    /// Returns the switch sources for this MIR.
-    #[inline]
-    pub(super) fn compute(
-        &self,
-        basic_blocks: &IndexVec<BasicBlock, BasicBlockData<'_>>,
-    ) -> &SwitchSources {
-        self.cache.get_or_init(|| {
-            let mut switch_sources: SwitchSources = FxHashMap::default();
-            for (bb, data) in basic_blocks.iter_enumerated() {
-                if let Some(Terminator {
-                    kind: TerminatorKind::SwitchInt { targets, .. }, ..
-                }) = &data.terminator
-                {
-                    for (value, target) in targets.iter() {
-                        switch_sources.entry((target, bb)).or_default().push(Some(value));
-                    }
-                    switch_sources.entry((targets.otherwise(), bb)).or_default().push(None);
-                }
-            }
-
-            switch_sources
-        })
-    }
-}
-
-impl<S: Encoder> Encodable<S> for SwitchSourceCache {
-    #[inline]
-    fn encode(&self, _s: &mut S) {}
-}
-
-impl<D: Decoder> Decodable<D> for SwitchSourceCache {
-    #[inline]
-    fn decode(_: &mut D) -> Self {
-        Self::new()
-    }
-}
-
-impl<CTX> HashStable<CTX> for SwitchSourceCache {
-    #[inline]
-    fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
-        // do nothing
-    }
-}
-
-TrivialTypeTraversalAndLiftImpls! {
-    SwitchSourceCache,
-}
index 6b4489026d3d379dee958125b73ced3eb3d40fb1..549bc65d6d79c7858a144fd038c107f1a07d85e5 100644 (file)
@@ -355,6 +355,12 @@ pub enum StatementKind<'tcx> {
     /// This avoids adding a new block and a terminator for simple intrinsics.
     Intrinsic(Box<NonDivergingIntrinsic<'tcx>>),
 
+    /// Instructs the const eval interpreter to increment a counter; this counter is used to track
+    /// how many steps the interpreter has taken. It is used to prevent the user from writing const
+    /// code that runs for too long or infinitely. Other than in the const eval interpreter, this
+    /// is a no-op.
+    ConstEvalCounter,
+
     /// No-op. Useful for deleting instructions without affecting statement indices.
     Nop,
 }
@@ -512,6 +518,16 @@ pub struct CopyNonOverlapping<'tcx> {
 ///     must also be `cleanup`. This is a part of the type system and checked statically, so it is
 ///     still an error to have such an edge in the CFG even if it's known that it won't be taken at
 ///     runtime.
+///  4. The control flow between cleanup blocks must look like an upside down tree. Roughly
+///     speaking, this means that control flow that looks like a V is allowed, while control flow
+///     that looks like a W is not. This is necessary to ensure that landing pad information can be
+///     correctly codegened on MSVC. More precisely:
+///
+///     Begin with the standard control flow graph `G`. Modify `G` as follows: for any two cleanup
+///     vertices `u` and `v` such that `u` dominates `v`, contract `u` and `v` into a single vertex,
+///     deleting self edges and duplicate edges in the process. Now remove all vertices from `G`
+///     that are not cleanup vertices or are not reachable. The resulting graph must be an inverted
+///     tree, that is each vertex may have at most one successor and there may be no cycles.
 #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)]
 pub enum TerminatorKind<'tcx> {
     /// Block has one successor; we continue execution there.
index 438f36373ca91b0682484f1052eefd7ad1aa889a..6e905224c1336b5d6e0d1839d078523058648834 100644 (file)
@@ -74,7 +74,7 @@ pub fn all_targets_mut(&mut self) -> &mut [BasicBlock] {
     }
 
     /// Finds the `BasicBlock` to which this `SwitchInt` will branch given the
-    /// specific value.  This cannot fail, as it'll return the `otherwise`
+    /// specific value. This cannot fail, as it'll return the `otherwise`
     /// branch if there's not a specific match for the value.
     pub fn target_for_value(&self, value: u128) -> BasicBlock {
         self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise())
index 0b461d1ce41c5f2559bda8ea0a82f3e06562431d..f37222cb29758cf827fe943b47d613b9be389bc9 100644 (file)
@@ -1,7 +1,4 @@
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::OnceCell;
 use rustc_index::bit_set::BitSet;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 
 use super::*;
 
@@ -339,50 +336,3 @@ pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorderIter
     let len = blocks.len();
     ReversePostorderIter { body, blocks, idx: len }
 }
-
-#[derive(Clone, Debug)]
-pub(super) struct PostorderCache {
-    cache: OnceCell<Vec<BasicBlock>>,
-}
-
-impl PostorderCache {
-    #[inline]
-    pub(super) fn new() -> Self {
-        PostorderCache { cache: OnceCell::new() }
-    }
-
-    /// Invalidates the postorder cache.
-    #[inline]
-    pub(super) fn invalidate(&mut self) {
-        self.cache = OnceCell::new();
-    }
-
-    /// Returns the `&[BasicBlocks]` represents the postorder graph for this MIR.
-    #[inline]
-    pub(super) fn compute(&self, body: &IndexVec<BasicBlock, BasicBlockData<'_>>) -> &[BasicBlock] {
-        self.cache.get_or_init(|| Postorder::new(body, START_BLOCK).map(|(bb, _)| bb).collect())
-    }
-}
-
-impl<S: Encoder> Encodable<S> for PostorderCache {
-    #[inline]
-    fn encode(&self, _s: &mut S) {}
-}
-
-impl<D: Decoder> Decodable<D> for PostorderCache {
-    #[inline]
-    fn decode(_: &mut D) -> Self {
-        Self::new()
-    }
-}
-
-impl<CTX> HashStable<CTX> for PostorderCache {
-    #[inline]
-    fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
-        // do nothing
-    }
-}
-
-TrivialTypeTraversalAndLiftImpls! {
-    PostorderCache,
-}
index e7cd497b206a9eacc500ea7f6bf76258e1b0c1a4..d44c6809bd8305da53c92e7b9c0878475781bec4 100644 (file)
@@ -4,6 +4,6 @@
 
 impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix<R, C> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 }
index 1a264d2d5af9a0d6ab1d8eebc2aaba14b9bde5ed..3ddac5e11fbc53bea3811686fdee4076d6d7a89e 100644 (file)
@@ -427,6 +427,7 @@ fn super_statement(&mut self,
                             }
                         }
                     }
+                    StatementKind::ConstEvalCounter => {}
                     StatementKind::Nop => {}
                 }
             }
index 8665591573695657dc3941e61f092529869f3327..1f1f4fc95b59aa666e791ef48a970466978d5a07 100644 (file)
 
     /// Given the def_id of a const-generic parameter, computes the associated default const
     /// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
-    query const_param_default(param: DefId) -> ty::Const<'tcx> {
+    query const_param_default(param: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
         desc { |tcx| "computing const default for a given parameter `{}`", tcx.def_path_str(param)  }
         cache_on_disk_if { param.is_local() }
         separate_provide_extern
         separate_provide_extern
     }
 
+    query is_type_alias_impl_trait(key: DefId) -> bool
+    {
+        desc { "determine whether the opaque is a type-alias impl trait" }
+        separate_provide_extern
+    }
+
     query analysis(key: ()) -> Result<(), ErrorGuaranteed> {
         eval_always
         desc { "running analysis passes on this crate" }
     /// ```
     ///
     /// Bounds from the parent (e.g. with nested impl trait) are not included.
-    query item_bounds(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
+    query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Predicate<'tcx>>> {
         desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
     }
 
         desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) }
     }
 
+    /// Create a list-like THIR representation for debugging.
+    query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> String {
+        no_hash
+        arena_cache
+        desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+    }
+
     /// Set of all the `DefId`s in this crate that have MIR associated with
     /// them. This includes all the body owners, but also things like struct
     /// constructors.
         }
     }
 
+    query mir_generator_witnesses(key: DefId) -> mir::GeneratorLayout<'tcx> {
+        arena_cache
+        desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
+        separate_provide_extern
+    }
+
+    query check_generator_obligations(key: LocalDefId) {
+        desc { |tcx| "verify auto trait bounds for generator interior type `{}`", tcx.def_path_str(key.to_def_id()) }
+    }
+
     /// MIR after our optimization passes have run. This is MIR that is ready
     /// for codegen. This is also the only query that can fetch non-local MIR, at present.
     query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> {
 
     /// Given an `impl_id`, return the trait it implements.
     /// Return `None` if this is an inherent impl.
-    query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
+    query impl_trait_ref(impl_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
         desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
         cache_on_disk_if { impl_id.is_local() }
         separate_provide_extern
     }
 
     /// Computes the signature of the function.
-    query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> {
+    query fn_sig(key: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {
         desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
     /// Determines whether an item is annotated with `doc(hidden)`.
     query is_doc_hidden(def_id: DefId) -> bool {
         desc { |tcx| "checking whether `{}` is `doc(hidden)`", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
     /// Determines whether an item is annotated with `doc(notable_trait)`.
     query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
         desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) }
     }
+    query check_is_object_safe(trait_id: DefId) -> bool {
+        desc { |tcx| "checking if trait `{}` is object safe", tcx.def_path_str(trait_id) }
+    }
 
     /// Gets the ParameterEnvironment for a given item; this environment
     /// will be in "user-facing" mode, meaning that it is suitable for
         Option<&'tcx FxHashMap<ItemLocalId, Region>> {
         desc { "looking up a named region" }
     }
-    query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxIndexSet<LocalDefId>> {
+    query is_late_bound_map(_: hir::OwnerId) -> Option<&'tcx FxIndexSet<ItemLocalId>> {
         desc { "testing if a region is late bound" }
     }
     /// For a given item's generic parameter, gets the default lifetimes to be used
     ///
     /// 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 5f320708c8416944466a25137159b95386baee11..6f2dac467532cdfb50e2b54b24276ff7278719ee 100644 (file)
@@ -29,6 +29,7 @@
 use std::fmt;
 use std::ops::Index;
 
+pub mod print;
 pub mod visit;
 
 macro_rules! thir_with_elements {
diff --git a/compiler/rustc_middle/src/thir/print.rs b/compiler/rustc_middle/src/thir/print.rs
new file mode 100644 (file)
index 0000000..60b903e
--- /dev/null
@@ -0,0 +1,881 @@
+use crate::thir::*;
+use crate::ty::{self, TyCtxt};
+
+use std::fmt::{self, Write};
+
+impl<'tcx> TyCtxt<'tcx> {
+    pub fn thir_tree_representation<'a>(self, thir: &'a Thir<'tcx>) -> String {
+        let mut printer = ThirPrinter::new(thir);
+        printer.print();
+        printer.into_buffer()
+    }
+}
+
+struct ThirPrinter<'a, 'tcx> {
+    thir: &'a Thir<'tcx>,
+    fmt: String,
+}
+
+const INDENT: &str = "    ";
+
+macro_rules! print_indented {
+    ($writer:ident, $s:expr, $indent_lvl:expr) => {
+        let indent = (0..$indent_lvl).map(|_| INDENT).collect::<Vec<_>>().concat();
+        writeln!($writer, "{}{}", indent, $s).expect("unable to write to ThirPrinter");
+    };
+}
+
+impl<'a, 'tcx> Write for ThirPrinter<'a, 'tcx> {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.fmt.push_str(s);
+        Ok(())
+    }
+}
+
+impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
+    fn new(thir: &'a Thir<'tcx>) -> Self {
+        Self { thir, fmt: String::new() }
+    }
+
+    fn print(&mut self) {
+        print_indented!(self, "params: [", 0);
+        for param in self.thir.params.iter() {
+            self.print_param(param, 1);
+        }
+        print_indented!(self, "]", 0);
+
+        print_indented!(self, "body:", 0);
+        let expr = ExprId::from_usize(self.thir.exprs.len() - 1);
+        self.print_expr(expr, 1);
+    }
+
+    fn into_buffer(self) -> String {
+        self.fmt
+    }
+
+    fn print_param(&mut self, param: &Param<'tcx>, depth_lvl: usize) {
+        let Param { pat, ty, ty_span, self_kind, hir_id } = param;
+
+        print_indented!(self, "Param {", depth_lvl);
+        print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+        print_indented!(self, format!("ty_span: {:?}", ty_span), depth_lvl + 1);
+        print_indented!(self, format!("self_kind: {:?}", self_kind), depth_lvl + 1);
+        print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 1);
+
+        if let Some(pat) = pat {
+            print_indented!(self, "param: Some( ", depth_lvl + 1);
+            self.print_pat(pat, depth_lvl + 2);
+            print_indented!(self, ")", depth_lvl + 1);
+        } else {
+            print_indented!(self, "param: None", depth_lvl + 1);
+        }
+
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_block(&mut self, block_id: BlockId, depth_lvl: usize) {
+        let Block {
+            targeted_by_break,
+            opt_destruction_scope,
+            span,
+            region_scope,
+            stmts,
+            expr,
+            safety_mode,
+        } = &self.thir.blocks[block_id];
+
+        print_indented!(self, "Block {", depth_lvl);
+        print_indented!(self, format!("targeted_by_break: {}", targeted_by_break), depth_lvl + 1);
+        print_indented!(
+            self,
+            format!("opt_destruction_scope: {:?}", opt_destruction_scope),
+            depth_lvl + 1
+        );
+        print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+        print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1);
+        print_indented!(self, format!("safety_mode: {:?}", safety_mode), depth_lvl + 1);
+
+        if stmts.len() > 0 {
+            print_indented!(self, "stmts: [", depth_lvl + 1);
+            for stmt in stmts.iter() {
+                self.print_stmt(*stmt, depth_lvl + 2);
+            }
+            print_indented!(self, "]", depth_lvl + 1);
+        } else {
+            print_indented!(self, "stmts: []", depth_lvl + 1);
+        }
+
+        if let Some(expr_id) = expr {
+            print_indented!(self, "expr:", depth_lvl + 1);
+            self.print_expr(*expr_id, depth_lvl + 2);
+        } else {
+            print_indented!(self, "expr: []", depth_lvl + 1);
+        }
+
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_stmt(&mut self, stmt_id: StmtId, depth_lvl: usize) {
+        let Stmt { kind, opt_destruction_scope } = &self.thir.stmts[stmt_id];
+
+        print_indented!(self, "Stmt {", depth_lvl);
+        print_indented!(
+            self,
+            format!("opt_destruction_scope: {:?}", opt_destruction_scope),
+            depth_lvl + 1
+        );
+
+        match kind {
+            StmtKind::Expr { scope, expr } => {
+                print_indented!(self, "kind: Expr {", depth_lvl + 1);
+                print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 2);
+                print_indented!(self, "expr:", depth_lvl + 2);
+                self.print_expr(*expr, depth_lvl + 3);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            StmtKind::Let {
+                remainder_scope,
+                init_scope,
+                pattern,
+                initializer,
+                else_block,
+                lint_level,
+            } => {
+                print_indented!(self, "kind: Let {", depth_lvl + 1);
+                print_indented!(
+                    self,
+                    format!("remainder_scope: {:?}", remainder_scope),
+                    depth_lvl + 2
+                );
+                print_indented!(self, format!("init_scope: {:?}", init_scope), depth_lvl + 2);
+
+                print_indented!(self, "pattern: ", depth_lvl + 2);
+                self.print_pat(pattern, depth_lvl + 3);
+                print_indented!(self, ",", depth_lvl + 2);
+
+                if let Some(init) = initializer {
+                    print_indented!(self, "initializer: Some(", depth_lvl + 2);
+                    self.print_expr(*init, depth_lvl + 3);
+                    print_indented!(self, ")", depth_lvl + 2);
+                } else {
+                    print_indented!(self, "initializer: None", depth_lvl + 2);
+                }
+
+                if let Some(else_block) = else_block {
+                    print_indented!(self, "else_block: Some(", depth_lvl + 2);
+                    self.print_block(*else_block, depth_lvl + 3);
+                    print_indented!(self, ")", depth_lvl + 2);
+                } else {
+                    print_indented!(self, "else_block: None", depth_lvl + 2);
+                }
+
+                print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+        }
+
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_expr(&mut self, expr: ExprId, depth_lvl: usize) {
+        let Expr { ty, temp_lifetime, span, kind } = &self.thir[expr];
+        print_indented!(self, "Expr {", depth_lvl);
+        print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+        print_indented!(self, format!("temp_lifetime: {:?}", temp_lifetime), depth_lvl + 1);
+        print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+        print_indented!(self, "kind: ", depth_lvl + 1);
+        self.print_expr_kind(kind, depth_lvl + 2);
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_expr_kind(&mut self, expr_kind: &ExprKind<'tcx>, depth_lvl: usize) {
+        use rustc_middle::thir::ExprKind::*;
+
+        match expr_kind {
+            Scope { region_scope, value, lint_level } => {
+                print_indented!(self, "Scope {", depth_lvl);
+                print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1);
+                print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1);
+                print_indented!(self, "value:", depth_lvl + 1);
+                self.print_expr(*value, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Box { value } => {
+                print_indented!(self, "Box {", depth_lvl);
+                self.print_expr(*value, depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            If { if_then_scope, cond, then, else_opt } => {
+                print_indented!(self, "If {", depth_lvl);
+                print_indented!(self, format!("if_then_scope: {:?}", if_then_scope), depth_lvl + 1);
+                print_indented!(self, "cond:", depth_lvl + 1);
+                self.print_expr(*cond, depth_lvl + 2);
+                print_indented!(self, "then:", depth_lvl + 1);
+                self.print_expr(*then, depth_lvl + 2);
+
+                if let Some(else_expr) = else_opt {
+                    print_indented!(self, "else:", depth_lvl + 1);
+                    self.print_expr(*else_expr, depth_lvl + 2);
+                }
+
+                print_indented!(self, "}", depth_lvl);
+            }
+            Call { fun, args, ty, from_hir_call, fn_span } => {
+                print_indented!(self, "Call {", depth_lvl);
+                print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+                print_indented!(self, format!("from_hir_call: {}", from_hir_call), depth_lvl + 1);
+                print_indented!(self, format!("fn_span: {:?}", fn_span), depth_lvl + 1);
+                print_indented!(self, "fun:", depth_lvl + 1);
+                self.print_expr(*fun, depth_lvl + 2);
+
+                if args.len() > 0 {
+                    print_indented!(self, "args: [", depth_lvl + 1);
+                    for arg in args.iter() {
+                        self.print_expr(*arg, depth_lvl + 2);
+                    }
+                    print_indented!(self, "]", depth_lvl + 1);
+                } else {
+                    print_indented!(self, "args: []", depth_lvl + 1);
+                }
+
+                print_indented!(self, "}", depth_lvl);
+            }
+            Deref { arg } => {
+                print_indented!(self, "Deref {", depth_lvl);
+                self.print_expr(*arg, depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Binary { op, lhs, rhs } => {
+                print_indented!(self, "Binary {", depth_lvl);
+                print_indented!(self, format!("op: {:?}", op), depth_lvl + 1);
+                print_indented!(self, "lhs:", depth_lvl + 1);
+                self.print_expr(*lhs, depth_lvl + 2);
+                print_indented!(self, "rhs:", depth_lvl + 1);
+                self.print_expr(*rhs, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            LogicalOp { op, lhs, rhs } => {
+                print_indented!(self, "LogicalOp {", depth_lvl);
+                print_indented!(self, format!("op: {:?}", op), depth_lvl + 1);
+                print_indented!(self, "lhs:", depth_lvl + 1);
+                self.print_expr(*lhs, depth_lvl + 2);
+                print_indented!(self, "rhs:", depth_lvl + 1);
+                self.print_expr(*rhs, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Unary { op, arg } => {
+                print_indented!(self, "Unary {", depth_lvl);
+                print_indented!(self, format!("op: {:?}", op), depth_lvl + 1);
+                print_indented!(self, "arg:", depth_lvl + 1);
+                self.print_expr(*arg, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Cast { source } => {
+                print_indented!(self, "Cast {", depth_lvl);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Use { source } => {
+                print_indented!(self, "Use {", depth_lvl);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            NeverToAny { source } => {
+                print_indented!(self, "NeverToAny {", depth_lvl);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Pointer { cast, source } => {
+                print_indented!(self, "Pointer {", depth_lvl);
+                print_indented!(self, format!("cast: {:?}", cast), depth_lvl + 1);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Loop { body } => {
+                print_indented!(self, "Loop (", depth_lvl);
+                print_indented!(self, "body:", depth_lvl + 1);
+                self.print_expr(*body, depth_lvl + 2);
+                print_indented!(self, ")", depth_lvl);
+            }
+            Let { expr, pat } => {
+                print_indented!(self, "Let {", depth_lvl);
+                print_indented!(self, "expr:", depth_lvl + 1);
+                self.print_expr(*expr, depth_lvl + 2);
+                print_indented!(self, format!("pat: {:?}", pat), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Match { scrutinee, arms } => {
+                print_indented!(self, "Match {", depth_lvl);
+                print_indented!(self, "scrutinee:", depth_lvl + 1);
+                self.print_expr(*scrutinee, depth_lvl + 2);
+
+                print_indented!(self, "arms: [", depth_lvl + 1);
+                for arm_id in arms.iter() {
+                    self.print_arm(*arm_id, depth_lvl + 2);
+                }
+                print_indented!(self, "]", depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Block { block } => self.print_block(*block, depth_lvl),
+            Assign { lhs, rhs } => {
+                print_indented!(self, "Assign {", depth_lvl);
+                print_indented!(self, "lhs:", depth_lvl + 1);
+                self.print_expr(*lhs, depth_lvl + 2);
+                print_indented!(self, "rhs:", depth_lvl + 1);
+                self.print_expr(*rhs, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            AssignOp { op, lhs, rhs } => {
+                print_indented!(self, "AssignOp {", depth_lvl);
+                print_indented!(self, format!("op: {:?}", op), depth_lvl + 1);
+                print_indented!(self, "lhs:", depth_lvl + 1);
+                self.print_expr(*lhs, depth_lvl + 2);
+                print_indented!(self, "rhs:", depth_lvl + 1);
+                self.print_expr(*rhs, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Field { lhs, variant_index, name } => {
+                print_indented!(self, "Field {", depth_lvl);
+                print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 1);
+                print_indented!(self, format!("name: {:?}", name), depth_lvl + 1);
+                print_indented!(self, "lhs:", depth_lvl + 1);
+                self.print_expr(*lhs, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Index { lhs, index } => {
+                print_indented!(self, "Index {", depth_lvl);
+                print_indented!(self, format!("index: {:?}", index), depth_lvl + 1);
+                print_indented!(self, "lhs:", depth_lvl + 1);
+                self.print_expr(*lhs, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            VarRef { id } => {
+                print_indented!(self, "VarRef {", depth_lvl);
+                print_indented!(self, format!("id: {:?}", id), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            UpvarRef { closure_def_id, var_hir_id } => {
+                print_indented!(self, "UpvarRef {", depth_lvl);
+                print_indented!(
+                    self,
+                    format!("closure_def_id: {:?}", closure_def_id),
+                    depth_lvl + 1
+                );
+                print_indented!(self, format!("var_hir_id: {:?}", var_hir_id), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Borrow { borrow_kind, arg } => {
+                print_indented!(self, "Borrow (", depth_lvl);
+                print_indented!(self, format!("borrow_kind: {:?}", borrow_kind), depth_lvl + 1);
+                print_indented!(self, "arg:", depth_lvl + 1);
+                self.print_expr(*arg, depth_lvl + 2);
+                print_indented!(self, ")", depth_lvl);
+            }
+            AddressOf { mutability, arg } => {
+                print_indented!(self, "AddressOf {", depth_lvl);
+                print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 1);
+                print_indented!(self, "arg:", depth_lvl + 1);
+                self.print_expr(*arg, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Break { label, value } => {
+                print_indented!(self, "Break (", depth_lvl);
+                print_indented!(self, format!("label: {:?}", label), depth_lvl + 1);
+
+                if let Some(value) = value {
+                    print_indented!(self, "value:", depth_lvl + 1);
+                    self.print_expr(*value, depth_lvl + 2);
+                }
+
+                print_indented!(self, ")", depth_lvl);
+            }
+            Continue { label } => {
+                print_indented!(self, "Continue {", depth_lvl);
+                print_indented!(self, format!("label: {:?}", label), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Return { value } => {
+                print_indented!(self, "Return {", depth_lvl);
+                print_indented!(self, "value:", depth_lvl + 1);
+
+                if let Some(value) = value {
+                    self.print_expr(*value, depth_lvl + 2);
+                }
+
+                print_indented!(self, "}", depth_lvl);
+            }
+            ConstBlock { did, substs } => {
+                print_indented!(self, "ConstBlock {", depth_lvl);
+                print_indented!(self, format!("did: {:?}", did), depth_lvl + 1);
+                print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Repeat { value, count } => {
+                print_indented!(self, "Repeat {", depth_lvl);
+                print_indented!(self, format!("count: {:?}", count), depth_lvl + 1);
+                print_indented!(self, "value:", depth_lvl + 1);
+                self.print_expr(*value, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Array { fields } => {
+                print_indented!(self, "Array {", depth_lvl);
+                print_indented!(self, "fields: [", depth_lvl + 1);
+                for field_id in fields.iter() {
+                    self.print_expr(*field_id, depth_lvl + 2);
+                }
+                print_indented!(self, "]", depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Tuple { fields } => {
+                print_indented!(self, "Tuple {", depth_lvl);
+                print_indented!(self, "fields: [", depth_lvl + 1);
+                for field_id in fields.iter() {
+                    self.print_expr(*field_id, depth_lvl + 2);
+                }
+                print_indented!(self, "]", depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Adt(adt_expr) => {
+                print_indented!(self, "Adt {", depth_lvl);
+                self.print_adt_expr(&**adt_expr, depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            PlaceTypeAscription { source, user_ty } => {
+                print_indented!(self, "PlaceTypeAscription {", depth_lvl);
+                print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            ValueTypeAscription { source, user_ty } => {
+                print_indented!(self, "ValueTypeAscription {", depth_lvl);
+                print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Closure(closure_expr) => {
+                print_indented!(self, "Closure {", depth_lvl);
+                print_indented!(self, "closure_expr:", depth_lvl + 1);
+                self.print_closure_expr(&**closure_expr, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Literal { lit, neg } => {
+                print_indented!(
+                    self,
+                    format!("Literal( lit: {:?}, neg: {:?})\n", lit, neg),
+                    depth_lvl
+                );
+            }
+            NonHirLiteral { lit, user_ty } => {
+                print_indented!(self, "NonHirLiteral {", depth_lvl);
+                print_indented!(self, format!("lit: {:?}", lit), depth_lvl + 1);
+                print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            ZstLiteral { user_ty } => {
+                print_indented!(self, format!("ZstLiteral(user_ty: {:?})", user_ty), depth_lvl);
+            }
+            NamedConst { def_id, substs, user_ty } => {
+                print_indented!(self, "NamedConst {", depth_lvl);
+                print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+                print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+                print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            ConstParam { param, def_id } => {
+                print_indented!(self, "ConstParam {", depth_lvl);
+                print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+                print_indented!(self, format!("param: {:?}", param), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            StaticRef { alloc_id, ty, def_id } => {
+                print_indented!(self, "StaticRef {", depth_lvl);
+                print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+                print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+                print_indented!(self, format!("alloc_id: {:?}", alloc_id), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            InlineAsm(expr) => {
+                print_indented!(self, "InlineAsm {", depth_lvl);
+                print_indented!(self, "expr:", depth_lvl + 1);
+                self.print_inline_asm_expr(&**expr, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            ThreadLocalRef(def_id) => {
+                print_indented!(self, "ThreadLocalRef {", depth_lvl);
+                print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl);
+            }
+            Yield { value } => {
+                print_indented!(self, "Yield {", depth_lvl);
+                print_indented!(self, "value:", depth_lvl + 1);
+                self.print_expr(*value, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+        }
+    }
+
+    fn print_adt_expr(&mut self, adt_expr: &AdtExpr<'tcx>, depth_lvl: usize) {
+        print_indented!(self, "adt_def:", depth_lvl);
+        self.print_adt_def(adt_expr.adt_def, depth_lvl + 1);
+        print_indented!(
+            self,
+            format!("variant_index: {:?}", adt_expr.variant_index),
+            depth_lvl + 1
+        );
+        print_indented!(self, format!("substs: {:?}", adt_expr.substs), depth_lvl + 1);
+        print_indented!(self, format!("user_ty: {:?}", adt_expr.user_ty), depth_lvl + 1);
+
+        for (i, field_expr) in adt_expr.fields.iter().enumerate() {
+            print_indented!(self, format!("field {}:", i), depth_lvl + 1);
+            self.print_expr(field_expr.expr, depth_lvl + 2);
+        }
+
+        if let Some(ref base) = adt_expr.base {
+            print_indented!(self, "base:", depth_lvl + 1);
+            self.print_fru_info(base, depth_lvl + 2);
+        } else {
+            print_indented!(self, "base: None", depth_lvl + 1);
+        }
+    }
+
+    fn print_adt_def(&mut self, adt_def: ty::AdtDef<'tcx>, depth_lvl: usize) {
+        print_indented!(self, "AdtDef {", depth_lvl);
+        print_indented!(self, format!("did: {:?}", adt_def.did()), depth_lvl + 1);
+        print_indented!(self, format!("variants: {:?}", adt_def.variants()), depth_lvl + 1);
+        print_indented!(self, format!("flags: {:?}", adt_def.flags()), depth_lvl + 1);
+        print_indented!(self, format!("repr: {:?}", adt_def.repr()), depth_lvl + 1);
+    }
+
+    fn print_fru_info(&mut self, fru_info: &FruInfo<'tcx>, depth_lvl: usize) {
+        print_indented!(self, "FruInfo {", depth_lvl);
+        print_indented!(self, "base: ", depth_lvl + 1);
+        self.print_expr(fru_info.base, depth_lvl + 2);
+        print_indented!(self, "field_types: [", depth_lvl + 1);
+        for ty in fru_info.field_types.iter() {
+            print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2);
+        }
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_arm(&mut self, arm_id: ArmId, depth_lvl: usize) {
+        print_indented!(self, "Arm {", depth_lvl);
+
+        let arm = &self.thir.arms[arm_id];
+        let Arm { pattern, guard, body, lint_level, scope, span } = arm;
+
+        print_indented!(self, "pattern: ", depth_lvl + 1);
+        self.print_pat(pattern, depth_lvl + 2);
+
+        if let Some(guard) = guard {
+            print_indented!(self, "guard: ", depth_lvl + 1);
+            self.print_guard(guard, depth_lvl + 2);
+        } else {
+            print_indented!(self, "guard: None", depth_lvl + 1);
+        }
+
+        print_indented!(self, "body: ", depth_lvl + 1);
+        self.print_expr(*body, depth_lvl + 2);
+        print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1);
+        print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 1);
+        print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_pat(&mut self, pat: &Box<Pat<'tcx>>, depth_lvl: usize) {
+        let Pat { ty, span, kind } = &**pat;
+
+        print_indented!(self, "Pat: {", depth_lvl);
+        print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+        print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+        self.print_pat_kind(kind, depth_lvl + 1);
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) {
+        print_indented!(self, "kind: PatKind {", depth_lvl);
+
+        match pat_kind {
+            PatKind::Wild => {
+                print_indented!(self, "Wild", depth_lvl + 1);
+            }
+            PatKind::AscribeUserType { ascription, subpattern } => {
+                print_indented!(self, "AscribeUserType: {", depth_lvl + 1);
+                print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2);
+                print_indented!(self, "subpattern: ", depth_lvl + 2);
+                self.print_pat(subpattern, depth_lvl + 3);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Binding { mutability, name, mode, var, ty, subpattern, is_primary } => {
+                print_indented!(self, "Binding {", depth_lvl + 1);
+                print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 2);
+                print_indented!(self, format!("name: {:?}", name), depth_lvl + 2);
+                print_indented!(self, format!("mode: {:?}", mode), depth_lvl + 2);
+                print_indented!(self, format!("var: {:?}", var), depth_lvl + 2);
+                print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2);
+                print_indented!(self, format!("is_primary: {:?}", is_primary), depth_lvl + 2);
+
+                if let Some(subpattern) = subpattern {
+                    print_indented!(self, "subpattern: Some( ", depth_lvl + 2);
+                    self.print_pat(subpattern, depth_lvl + 3);
+                    print_indented!(self, ")", depth_lvl + 2);
+                } else {
+                    print_indented!(self, "subpattern: None", depth_lvl + 2);
+                }
+
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Variant { adt_def, substs, variant_index, subpatterns } => {
+                print_indented!(self, "Variant {", depth_lvl + 1);
+                print_indented!(self, "adt_def: ", depth_lvl + 2);
+                self.print_adt_def(*adt_def, depth_lvl + 3);
+                print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 2);
+                print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 2);
+
+                if subpatterns.len() > 0 {
+                    print_indented!(self, "subpatterns: [", depth_lvl + 2);
+                    for field_pat in subpatterns.iter() {
+                        self.print_pat(&field_pat.pattern, depth_lvl + 3);
+                    }
+                    print_indented!(self, "]", depth_lvl + 2);
+                } else {
+                    print_indented!(self, "subpatterns: []", depth_lvl + 2);
+                }
+
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Leaf { subpatterns } => {
+                print_indented!(self, "Leaf { ", depth_lvl + 1);
+                print_indented!(self, "subpatterns: [", depth_lvl + 2);
+                for field_pat in subpatterns.iter() {
+                    self.print_pat(&field_pat.pattern, depth_lvl + 3);
+                }
+                print_indented!(self, "]", depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Deref { subpattern } => {
+                print_indented!(self, "Deref { ", depth_lvl + 1);
+                print_indented!(self, "subpattern: ", depth_lvl + 2);
+                self.print_pat(subpattern, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Constant { value } => {
+                print_indented!(self, "Constant {", depth_lvl + 1);
+                print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Range(pat_range) => {
+                print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1);
+            }
+            PatKind::Slice { prefix, slice, suffix } => {
+                print_indented!(self, "Slice {", depth_lvl + 1);
+
+                print_indented!(self, "prefix: [", depth_lvl + 2);
+                for prefix_pat in prefix.iter() {
+                    self.print_pat(prefix_pat, depth_lvl + 3);
+                }
+                print_indented!(self, "]", depth_lvl + 2);
+
+                if let Some(slice) = slice {
+                    print_indented!(self, "slice: ", depth_lvl + 2);
+                    self.print_pat(slice, depth_lvl + 3);
+                }
+
+                print_indented!(self, "suffix: [", depth_lvl + 2);
+                for suffix_pat in suffix.iter() {
+                    self.print_pat(suffix_pat, depth_lvl + 3);
+                }
+                print_indented!(self, "]", depth_lvl + 2);
+
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Array { prefix, slice, suffix } => {
+                print_indented!(self, "Array {", depth_lvl + 1);
+
+                print_indented!(self, "prefix: [", depth_lvl + 2);
+                for prefix_pat in prefix.iter() {
+                    self.print_pat(prefix_pat, depth_lvl + 3);
+                }
+                print_indented!(self, "]", depth_lvl + 2);
+
+                if let Some(slice) = slice {
+                    print_indented!(self, "slice: ", depth_lvl + 2);
+                    self.print_pat(slice, depth_lvl + 3);
+                }
+
+                print_indented!(self, "suffix: [", depth_lvl + 2);
+                for suffix_pat in suffix.iter() {
+                    self.print_pat(suffix_pat, depth_lvl + 3);
+                }
+                print_indented!(self, "]", depth_lvl + 2);
+
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            PatKind::Or { pats } => {
+                print_indented!(self, "Or {", depth_lvl + 1);
+                print_indented!(self, "pats: [", depth_lvl + 2);
+                for pat in pats.iter() {
+                    self.print_pat(pat, depth_lvl + 3);
+                }
+                print_indented!(self, "]", depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+        }
+
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_guard(&mut self, guard: &Guard<'tcx>, depth_lvl: usize) {
+        print_indented!(self, "Guard {", depth_lvl);
+
+        match guard {
+            Guard::If(expr_id) => {
+                print_indented!(self, "If (", depth_lvl + 1);
+                self.print_expr(*expr_id, depth_lvl + 2);
+                print_indented!(self, ")", depth_lvl + 1);
+            }
+            Guard::IfLet(pat, expr_id) => {
+                print_indented!(self, "IfLet (", depth_lvl + 1);
+                self.print_pat(pat, depth_lvl + 2);
+                print_indented!(self, ",", depth_lvl + 1);
+                self.print_expr(*expr_id, depth_lvl + 2);
+                print_indented!(self, ")", depth_lvl + 1);
+            }
+        }
+
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_closure_expr(&mut self, expr: &ClosureExpr<'tcx>, depth_lvl: usize) {
+        let ClosureExpr { closure_id, substs, upvars, movability, fake_reads } = expr;
+
+        print_indented!(self, "ClosureExpr {", depth_lvl);
+        print_indented!(self, format!("closure_id: {:?}", closure_id), depth_lvl + 1);
+        print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1);
+
+        if upvars.len() > 0 {
+            print_indented!(self, "upvars: [", depth_lvl + 1);
+            for upvar in upvars.iter() {
+                self.print_expr(*upvar, depth_lvl + 2);
+                print_indented!(self, ",", depth_lvl + 1);
+            }
+            print_indented!(self, "]", depth_lvl + 1);
+        } else {
+            print_indented!(self, "upvars: []", depth_lvl + 1);
+        }
+
+        print_indented!(self, format!("movability: {:?}", movability), depth_lvl + 1);
+
+        if fake_reads.len() > 0 {
+            print_indented!(self, "fake_reads: [", depth_lvl + 1);
+            for (fake_read_expr, cause, hir_id) in fake_reads.iter() {
+                print_indented!(self, "(", depth_lvl + 2);
+                self.print_expr(*fake_read_expr, depth_lvl + 3);
+                print_indented!(self, ",", depth_lvl + 2);
+                print_indented!(self, format!("cause: {:?}", cause), depth_lvl + 3);
+                print_indented!(self, ",", depth_lvl + 2);
+                print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 3);
+                print_indented!(self, "),", depth_lvl + 2);
+            }
+            print_indented!(self, "]", depth_lvl + 1);
+        } else {
+            print_indented!(self, "fake_reads: []", depth_lvl + 1);
+        }
+
+        print_indented!(self, "}", depth_lvl);
+    }
+
+    fn print_inline_asm_expr(&mut self, expr: &InlineAsmExpr<'tcx>, depth_lvl: usize) {
+        let InlineAsmExpr { template, operands, options, line_spans } = expr;
+
+        print_indented!(self, "InlineAsmExpr {", depth_lvl);
+
+        print_indented!(self, "template: [", depth_lvl + 1);
+        for template_piece in template.iter() {
+            print_indented!(self, format!("{:?}", template_piece), depth_lvl + 2);
+        }
+        print_indented!(self, "]", depth_lvl + 1);
+
+        print_indented!(self, "operands: [", depth_lvl + 1);
+        for operand in operands.iter() {
+            self.print_inline_operand(operand, depth_lvl + 2);
+        }
+        print_indented!(self, "]", depth_lvl + 1);
+
+        print_indented!(self, format!("options: {:?}", options), depth_lvl + 1);
+        print_indented!(self, format!("line_spans: {:?}", line_spans), depth_lvl + 1);
+    }
+
+    fn print_inline_operand(&mut self, operand: &InlineAsmOperand<'tcx>, depth_lvl: usize) {
+        match operand {
+            InlineAsmOperand::In { reg, expr } => {
+                print_indented!(self, "InlineAsmOperand::In {", depth_lvl);
+                print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1);
+                print_indented!(self, "expr: ", depth_lvl + 1);
+                self.print_expr(*expr, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            InlineAsmOperand::Out { reg, late, expr } => {
+                print_indented!(self, "InlineAsmOperand::Out {", depth_lvl);
+                print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1);
+                print_indented!(self, format!("late: {:?}", late), depth_lvl + 1);
+
+                if let Some(out) = expr {
+                    print_indented!(self, "place: Some( ", depth_lvl + 1);
+                    self.print_expr(*out, depth_lvl + 2);
+                    print_indented!(self, ")", depth_lvl + 1);
+                } else {
+                    print_indented!(self, "place: None", depth_lvl + 1);
+                }
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            InlineAsmOperand::InOut { reg, late, expr } => {
+                print_indented!(self, "InlineAsmOperand::InOut {", depth_lvl);
+                print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1);
+                print_indented!(self, format!("late: {:?}", late), depth_lvl + 1);
+                print_indented!(self, "expr: ", depth_lvl + 1);
+                self.print_expr(*expr, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
+                print_indented!(self, "InlineAsmOperand::SplitInOut {", depth_lvl);
+                print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1);
+                print_indented!(self, format!("late: {:?}", late), depth_lvl + 1);
+                print_indented!(self, "in_expr: ", depth_lvl + 1);
+                self.print_expr(*in_expr, depth_lvl + 2);
+
+                if let Some(out_expr) = out_expr {
+                    print_indented!(self, "out_expr: Some( ", depth_lvl + 1);
+                    self.print_expr(*out_expr, depth_lvl + 2);
+                    print_indented!(self, ")", depth_lvl + 1);
+                } else {
+                    print_indented!(self, "out_expr: None", depth_lvl + 1);
+                }
+
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            InlineAsmOperand::Const { value, span } => {
+                print_indented!(self, "InlineAsmOperand::Const {", depth_lvl);
+                print_indented!(self, format!("value: {:?}", value), depth_lvl + 1);
+                print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            InlineAsmOperand::SymFn { value, span } => {
+                print_indented!(self, "InlineAsmOperand::SymFn {", depth_lvl);
+                print_indented!(self, format!("value: {:?}", *value), depth_lvl + 1);
+                print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+            InlineAsmOperand::SymStatic { def_id } => {
+                print_indented!(self, "InlineAsmOperand::SymStatic {", depth_lvl);
+                print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
+        }
+    }
+}
index dd75b0d9ebc23e30de15728d67d877fb48e52a00..fcc8f457a8b7887296526a2d1093a5b3f86027a6 100644 (file)
@@ -159,18 +159,20 @@ fn debug_ty(ty: &chalk_ir::Ty<Self>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt
             }
             chalk_ir::TyKind::Array(ty, len) => Some(write!(fmt, "[{:?}; {:?}]", ty, len)),
             chalk_ir::TyKind::Slice(ty) => Some(write!(fmt, "[{:?}]", ty)),
-            chalk_ir::TyKind::Tuple(len, substs) => Some((|| {
-                write!(fmt, "(")?;
-                for (idx, substitution) in substs.interned().iter().enumerate() {
-                    if idx == *len && *len != 1 {
-                        // Don't add a trailing comma if the tuple has more than one element
-                        write!(fmt, "{:?}", substitution)?;
-                    } else {
-                        write!(fmt, "{:?},", substitution)?;
+            chalk_ir::TyKind::Tuple(len, substs) => Some(
+                try {
+                    write!(fmt, "(")?;
+                    for (idx, substitution) in substs.interned().iter().enumerate() {
+                        if idx == *len && *len != 1 {
+                            // Don't add a trailing comma if the tuple has more than one element
+                            write!(fmt, "{:?}", substitution)?;
+                        } else {
+                            write!(fmt, "{:?},", substitution)?;
+                        }
                     }
-                }
-                write!(fmt, ")")
-            })()),
+                    write!(fmt, ")")?;
+                },
+            ),
             _ => None,
         }
     }
index d00b26a5a3d0b42baafca1d795332bbfc0ddbdcc..cf3dce48064923a0b582c25ca028827c673eecdf 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;
@@ -36,7 +37,7 @@
 
 /// Depending on the stage of compilation, we want projection to be
 /// more or less conservative.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)]
 pub enum Reveal {
     /// At type-checking time, we refuse to project any associated
     /// type that is marked `default`. Non-`default` ("final") types
@@ -89,7 +90,8 @@ pub enum Reveal {
 ///
 /// We do not want to intern this as there are a lot of obligation causes which
 /// only live for a short period of time.
-#[derive(Clone, Debug, PartialEq, Eq, Lift)]
+#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(TypeVisitable, TypeFoldable)]
 pub struct ObligationCause<'tcx> {
     pub span: Span,
 
@@ -99,7 +101,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 +122,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 +139,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 {
@@ -196,14 +198,16 @@ pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(TypeVisitable, TypeFoldable)]
 pub struct UnifyReceiverContext<'tcx> {
     pub assoc_item: ty::AssocItem,
     pub param_env: ty::ParamEnv<'tcx>,
     pub substs: SubstsRef<'tcx>,
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Lift, Default)]
+#[derive(Clone, PartialEq, Eq, Hash, Lift, Default, HashStable)]
+#[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)]
 pub struct InternedObligationCauseCode<'tcx> {
     /// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of
     /// the time). `Some` otherwise.
@@ -238,7 +242,8 @@ fn deref(&self) -> &Self::Target {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(TypeVisitable, TypeFoldable)]
 pub enum ObligationCauseCode<'tcx> {
     /// Not well classified or should be obvious from the span.
     MiscObligation,
@@ -446,7 +451,8 @@ pub enum ObligationCauseCode<'tcx> {
 /// This information is used to obtain an `hir::Ty`, which
 /// we can walk in order to obtain precise spans for any
 /// 'nested' types (e.g. `Foo` in `Option<Foo>`).
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)]
+#[derive(TypeVisitable, TypeFoldable)]
 pub enum WellFormedLoc {
     /// Use the type of the provided definition.
     Ty(LocalDefId),
@@ -463,7 +469,8 @@ pub enum WellFormedLoc {
     },
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(TypeVisitable, TypeFoldable)]
 pub struct ImplDerivedObligationCause<'tcx> {
     pub derived: DerivedObligationCause<'tcx>,
     pub impl_def_id: DefId,
@@ -517,7 +524,8 @@ fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option<StatementAsExpression> {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(TypeVisitable, TypeFoldable)]
 pub struct MatchExpressionArmCause<'tcx> {
     pub arm_block_id: Option<hir::HirId>,
     pub arm_ty: Ty<'tcx>,
@@ -533,7 +541,7 @@ pub struct MatchExpressionArmCause<'tcx> {
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-#[derive(Lift, TypeFoldable, TypeVisitable)]
+#[derive(Lift, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
 pub struct IfExpressionCause<'tcx> {
     pub then_id: hir::HirId,
     pub else_id: hir::HirId,
@@ -543,7 +551,8 @@ pub struct IfExpressionCause<'tcx> {
     pub opt_suggest_box_span: Option<Span>,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(TypeVisitable, TypeFoldable)]
 pub struct DerivedObligationCause<'tcx> {
     /// The trait predicate of the parent obligation that led to the
     /// current obligation. Note that only trait obligations lead to
index 543f5b87e00bccd3a0c887f9c06f31ce3149f923..615154a55e586dee13ce18a7e4fbb0d87ea96310 100644 (file)
@@ -8,9 +8,8 @@
 use crate::error::DropCheckOverflow;
 use crate::infer::canonical::{Canonical, QueryResponse};
 use crate::ty::error::TypeError;
-use crate::ty::subst::{GenericArg, SubstsRef};
+use crate::ty::subst::GenericArg;
 use crate::ty::{self, Ty, TyCtxt};
-use rustc_hir::def_id::DefId;
 use rustc_span::source_map::Span;
 
 pub mod type_op {
@@ -214,6 +213,5 @@ pub struct NormalizationResult<'tcx> {
 pub enum OutlivesBound<'tcx> {
     RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
     RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
-    RegionSubProjection(ty::Region<'tcx>, ty::AliasTy<'tcx>),
-    RegionSubOpaque(ty::Region<'tcx>, DefId, SubstsRef<'tcx>),
+    RegionSubAlias(ty::Region<'tcx>, ty::AliasTy<'tcx>),
 }
index d3d667f68407fde123e0407e22ba4caa1d0a1095..099a784511827b2ffe69250ccf2155b7200f4765 100644 (file)
@@ -188,7 +188,7 @@ pub fn repr(self) -> ReprOptions {
     }
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable, TyEncodable, TyDecodable)]
 pub enum AdtKind {
     Struct,
     Union,
index 55ee5bd2f810d0999641b9e490e27c780cdab700..71cecfb558fb282c48055ff139d96fb399c88a07 100644 (file)
@@ -37,6 +37,11 @@ pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
         Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
     }
 
+    /// Gets the defaultness of the associated item.
+    /// To get the default associated type, use the [`type_of`] query on the
+    /// [`DefId`] of the type.
+    ///
+    /// [`type_of`]: crate::ty::TyCtxt::type_of
     pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
         tcx.impl_defaultness(self.def_id)
     }
@@ -72,9 +77,9 @@ pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
             ty::AssocKind::Fn => {
                 // We skip the binder here because the binder would deanonymize all
                 // late-bound regions, and we don't want method signatures to show up
-                // `as for<'r> fn(&'r MyType)`.  Pretty-printing handles late-bound
+                // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
                 // regions just fine, showing `fn(&MyType)`.
-                tcx.fn_sig(self.def_id).skip_binder().to_string()
+                tcx.fn_sig(self.def_id).subst_identity().skip_binder().to_string()
             }
             ty::AssocKind::Type => format!("type {};", self.name),
             ty::AssocKind::Const => {
@@ -125,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 8cc8286c1dbe67ea25fba051aab058f27ba18d2b..b9a1e23879cca7f9b407633698f06c8717f74401 100644 (file)
@@ -157,6 +157,14 @@ fn encode(&self, e: &mut E) {
     }
 }
 
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::ParamEnv<'tcx> {
+    fn encode(&self, e: &mut E) {
+        self.caller_bounds().encode(e);
+        self.reveal().encode(e);
+        self.constness().encode(e);
+    }
+}
+
 #[inline]
 fn decode_arena_allocable<
     'tcx,
@@ -280,8 +288,17 @@ fn decode(decoder: &mut D) -> Self {
     }
 }
 
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::ParamEnv<'tcx> {
+    fn decode(d: &mut D) -> Self {
+        let caller_bounds = Decodable::decode(d);
+        let reveal = Decodable::decode(d);
+        let constness = Decodable::decode(d);
+        ty::ParamEnv::new(caller_bounds, reveal, constness)
+    }
+}
+
 macro_rules! impl_decodable_via_ref {
-    ($($t:ty),+) => {
+    ($($t:ty,)+) => {
         $(impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for $t {
             fn decode(decoder: &mut D) -> Self {
                 RefDecodable::decode(decoder)
@@ -373,6 +390,15 @@ fn decode(decoder: &mut D) -> &'tcx Self {
     }
 }
 
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Predicate<'tcx>> {
+    fn decode(decoder: &mut D) -> &'tcx Self {
+        let len = decoder.read_usize();
+        let predicates: Vec<_> =
+            (0..len).map::<ty::Predicate<'tcx>, _>(|_| Decodable::decode(decoder)).collect();
+        decoder.interner().intern_predicates(&predicates)
+    }
+}
+
 impl_decodable_via_ref! {
     &'tcx ty::TypeckResults<'tcx>,
     &'tcx ty::List<Ty<'tcx>>,
@@ -382,7 +408,8 @@ fn decode(decoder: &mut D) -> &'tcx Self {
     &'tcx mir::UnsafetyCheckResult,
     &'tcx mir::BorrowCheckResult<'tcx>,
     &'tcx mir::coverage::CodeRegion,
-    &'tcx ty::List<ty::BoundVariableKind>
+    &'tcx ty::List<ty::BoundVariableKind>,
+    &'tcx ty::List<ty::Predicate<'tcx>>,
 }
 
 #[macro_export]
@@ -519,6 +546,8 @@ fn decode(decoder: &mut D) -> Self {
 impl_binder_encode_decode! {
     &'tcx ty::List<Ty<'tcx>>,
     ty::FnSig<'tcx>,
+    ty::Predicate<'tcx>,
+    ty::TraitPredicate<'tcx>,
     ty::ExistentialPredicate<'tcx>,
     ty::TraitRef<'tcx>,
     Vec<ty::GeneratorInteriorTypeCause<'tcx>>,
index 152a7e9d43fa4e32e7c6754efb5397cdc782beeb..65cbac3e8f1cd5f341e7a0054a03be00c6c1bc81 100644 (file)
@@ -239,7 +239,7 @@ pub fn is_ct_infer(self) -> bool {
     }
 }
 
-pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> Const<'_> {
+pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Const<'_>> {
     let default_def_id = match tcx.hir().get_by_def_id(def_id.expect_local()) {
         hir::Node::GenericParam(hir::GenericParam {
             kind: hir::GenericParamKind::Const { default: Some(ac), .. },
@@ -250,5 +250,5 @@ pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> Const<'_> {
             "`const_param_default` expected a generic parameter with a constant"
         ),
     };
-    Const::from_anon_const(tcx, default_def_id)
+    ty::EarlyBinder(Const::from_anon_const(tcx, default_def_id))
 }
index 63f31e5a11f39e96e835a308d2e12653767d22f7..b63b9e754cf466a963adc68740971e5f6fa0e0ff 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};
@@ -75,6 +77,8 @@
 use std::mem;
 use std::ops::{Bound, Deref};
 
+const TINY_CONST_EVAL_LIMIT: Limit = Limit(20);
+
 pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
     /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
     fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
@@ -874,7 +878,7 @@ pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable {
         self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
 
         // Leak a read lock once we start iterating on definitions, to prevent adding new ones
-        // while iterating.  If some query needs to add definitions, it should be `ensure`d above.
+        // while iterating. If some query needs to add definitions, it should be `ensure`d above.
         let definitions = self.untracked.definitions.leak();
         definitions.def_path_table()
     }
@@ -886,7 +890,7 @@ pub fn def_path_hash_to_def_index_map(
         // definitions change.
         self.ensure().hir_crate(());
         // Leak a read lock once we start iterating on definitions, to prevent adding new ones
-        // while iterating.  If some query needs to add definitions, it should be `ensure`d above.
+        // while iterating. If some query needs to add definitions, it should be `ensure`d above.
         let definitions = self.untracked.definitions.leak();
         definitions.def_path_hash_to_def_index_map()
     }
@@ -997,6 +1001,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) {
@@ -1078,7 +1106,11 @@ pub fn move_size_limit(self) -> Limit {
     }
 
     pub fn const_eval_limit(self) -> Limit {
-        self.limits(()).const_eval_limit
+        if self.sess.opts.unstable_opts.tiny_const_eval_limit {
+            TINY_CONST_EVAL_LIMIT
+        } else {
+            self.limits(()).const_eval_limit
+        }
     }
 
     pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx {
@@ -1188,178 +1220,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
@@ -1452,6 +1312,7 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                     Placeholder,
                     Generator,
                     GeneratorWitness,
+                    GeneratorWitnessMIR,
                     Dynamic,
                     Closure,
                     Tuple,
@@ -1952,6 +1813,20 @@ pub fn mk_generator_witness(self, types: ty::Binder<'tcx, &'tcx List<Ty<'tcx>>>)
         self.mk_ty(GeneratorWitness(types))
     }
 
+    /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes.
+    pub fn mk_task_context(self) -> Ty<'tcx> {
+        let context_did = self.require_lang_item(LangItem::Context, None);
+        let context_adt_ref = self.adt_def(context_did);
+        let context_substs = self.intern_substs(&[self.lifetimes.re_erased.into()]);
+        let context_ty = self.mk_adt(context_adt_ref, context_substs);
+        self.mk_mut_ref(self.lifetimes.re_erased, context_ty)
+    }
+
+    #[inline]
+    pub fn mk_generator_witness_mir(self, id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
+        self.mk_ty(GeneratorWitnessMIR(id, substs))
+    }
+
     #[inline]
     pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> {
         self.mk_ty_infer(TyVar(v))
@@ -2288,10 +2163,7 @@ pub fn named_region(self, id: HirId) -> Option<resolve_lifetime::Region> {
     }
 
     pub fn is_late_bound(self, id: HirId) -> bool {
-        self.is_late_bound_map(id.owner.def_id).map_or(false, |set| {
-            let def_id = self.hir().local_def_id(id);
-            set.contains(&def_id)
-        })
+        self.is_late_bound_map(id.owner).map_or(false, |set| set.contains(&id.local_id))
     }
 
     pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
@@ -2383,12 +2255,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 8c22df7395f1052669ad14f2e36cc7e187bf4b23..4b4518f61e8d39b444bb4716a0ff13cf1966b54d 100644 (file)
@@ -4,12 +4,13 @@
 
 use crate::ty::{
     visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, InferConst, InferTy, Opaque,
-    PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
+    PolyTraitPredicate, Projection, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
 };
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg};
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::WherePredicate;
 use rustc_span::Span;
@@ -17,7 +18,7 @@
 
 impl<'tcx> IntoDiagnosticArg for Ty<'tcx> {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        format!("{}", self).into_diagnostic_arg()
+        self.to_string().into_diagnostic_arg()
     }
 }
 
@@ -443,7 +444,7 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
     type BreakTy = ();
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match t.kind() {
+        match *t.kind() {
             Infer(InferTy::TyVar(_)) if self.infer_suggestable => {}
 
             FnDef(..)
@@ -458,9 +459,9 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
 
             Alias(Opaque, AliasTy { def_id, .. }) => {
-                let parent = self.tcx.parent(*def_id);
-                if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
-                    && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = self.tcx.type_of(parent).kind()
+                let parent = self.tcx.parent(def_id);
+                if let DefKind::TyAlias | DefKind::AssocTy = self.tcx.def_kind(parent)
+                    && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *self.tcx.type_of(parent).kind()
                     && parent_opaque_def_id == def_id
                 {
                     // Okay
@@ -469,6 +470,12 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 }
             }
 
+            Alias(Projection, AliasTy { def_id, .. }) => {
+                if self.tcx.def_kind(def_id) != DefKind::AssocTy {
+                    return ControlFlow::Break(());
+                }
+            }
+
             Param(param) => {
                 // FIXME: It would be nice to make this not use string manipulation,
                 // but it's pretty hard to do this, since `ty::ParamTy` is missing
index 5d394f71f0d764024b33c0f2e4f047a61a8743e9..d83fc95ac4eeb04995110044354443608befb283 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,
@@ -331,7 +325,8 @@ pub fn sort_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
             ty::Dynamic(..) => "trait object".into(),
             ty::Closure(..) => "closure".into(),
             ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
-            ty::GeneratorWitness(..) => "generator witness".into(),
+            ty::GeneratorWitness(..) |
+            ty::GeneratorWitnessMIR(..) => "generator witness".into(),
             ty::Tuple(..) => "tuple".into(),
             ty::Infer(ty::TyVar(_)) => "inferred type".into(),
             ty::Infer(ty::IntVar(_)) => "integer".into(),
@@ -379,7 +374,7 @@ pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
             ty::Dynamic(..) => "trait object".into(),
             ty::Closure(..) => "closure".into(),
             ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
-            ty::GeneratorWitness(..) => "generator witness".into(),
+            ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => "generator witness".into(),
             ty::Tuple(..) => "tuple".into(),
             ty::Placeholder(..) => "higher-ranked type".into(),
             ty::Bound(..) => "bound type variable".into(),
@@ -391,620 +386,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 +428,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 f785fb5c4b9be5b5c57f78104e7895b029bcbabf..9afa37e9ef3ee137467dcaf2c7d1944b090bead5 100644 (file)
@@ -32,6 +32,7 @@ pub enum SimplifiedType {
     ClosureSimplifiedType(DefId),
     GeneratorSimplifiedType(DefId),
     GeneratorWitnessSimplifiedType(usize),
+    GeneratorWitnessMIRSimplifiedType(DefId),
     FunctionSimplifiedType(usize),
     PlaceholderSimplifiedType,
 }
@@ -108,6 +109,7 @@ pub fn simplify_type<'tcx>(
         ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)),
         ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)),
         ty::GeneratorWitness(tys) => Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len())),
+        ty::GeneratorWitnessMIR(def_id, _) => Some(GeneratorWitnessMIRSimplifiedType(def_id)),
         ty::Never => Some(NeverSimplifiedType),
         ty::Tuple(tys) => Some(TupleSimplifiedType(tys.len())),
         ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())),
@@ -139,7 +141,8 @@ pub fn def(self) -> Option<DefId> {
             | ForeignSimplifiedType(d)
             | TraitSimplifiedType(d)
             | ClosureSimplifiedType(d)
-            | GeneratorSimplifiedType(d) => Some(d),
+            | GeneratorSimplifiedType(d)
+            | GeneratorWitnessMIRSimplifiedType(d) => Some(d),
             _ => None,
         }
     }
@@ -208,6 +211,7 @@ pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -
             | ty::Closure(..)
             | ty::Generator(..)
             | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..)
             | ty::Placeholder(..)
             | ty::Bound(..)
             | ty::Infer(_) => bug!("unexpected impl_ty: {impl_ty}"),
@@ -306,7 +310,7 @@ pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -
 
             ty::Error(_) => true,
 
-            ty::GeneratorWitness(..) | ty::Bound(..) => {
+            ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) | ty::Bound(..) => {
                 bug!("unexpected obligation type: {:?}", obligation_ty)
             }
         }
index b7eafc4b437385ac986f29b2c0ef8d09f4972246..dc6f5851b7d883ad6a2fd843615d23446f06a87b 100644 (file)
@@ -125,6 +125,16 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
                 self.bound_computation(ts, |flags, ts| flags.add_tys(ts));
             }
 
+            &ty::GeneratorWitnessMIR(_, ref substs) => {
+                let should_remove_further_specializable =
+                    !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+                self.add_substs(substs);
+                if should_remove_further_specializable {
+                    self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
+                }
+                self.add_flags(TypeFlags::HAS_TY_GENERATOR);
+            }
+
             &ty::Closure(_, substs) => {
                 let substs = substs.as_closure();
                 let should_remove_further_specializable =
index 09fee0c3f7c30819138b4df81f49295aa0a6d031..6b9a37d848da2966870256959d7e1d10ecb672cc 100644 (file)
@@ -290,7 +290,7 @@ pub struct RegionFolder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
 
     /// Stores the index of a binder *just outside* the stuff we have
-    /// visited.  So this begins as INNERMOST; when we pass through a
+    /// visited. So this begins as INNERMOST; when we pass through a
     /// binder, it is incremented (via `shift_in`).
     current_index: ty::DebruijnIndex,
 
index 705adecd3b90f517b9d9c5ed814fdcbaecf4c111..801ca6004456827daba7eaf84db464e153ac1387 100644 (file)
@@ -88,7 +88,7 @@ pub fn default_value<'tcx>(
                 Some(tcx.bound_type_of(self.def_id).map_bound(|t| t.into()))
             }
             GenericParamDefKind::Const { has_default } if has_default => {
-                Some(tcx.bound_const_param_default(self.def_id).map_bound(|c| c.into()))
+                Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
             }
             _ => None,
         }
@@ -341,15 +341,9 @@ pub fn instantiate_own(
         &self,
         tcx: TyCtxt<'tcx>,
         substs: SubstsRef<'tcx>,
-    ) -> InstantiatedPredicates<'tcx> {
-        InstantiatedPredicates {
-            predicates: self
-                .predicates
-                .iter()
-                .map(|(p, _)| EarlyBinder(*p).subst(tcx, substs))
-                .collect(),
-            spans: self.predicates.iter().map(|(_, sp)| *sp).collect(),
-        }
+    ) -> impl Iterator<Item = (Predicate<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator
+    {
+        EarlyBinder(self.predicates).subst_iter_copied(tcx, substs)
     }
 
     #[instrument(level = "debug", skip(self, tcx))]
index 4ee4d7caec1f3c86593240e6a3da72eddc30202b..8b4fccc58bd4447819f4ad763867891d7a9acae0 100644 (file)
@@ -459,7 +459,7 @@ pub fn resolve_for_vtable(
         substs: SubstsRef<'tcx>,
     ) -> Option<Instance<'tcx>> {
         debug!("resolve_for_vtable(def_id={:?}, substs={:?})", def_id, substs);
-        let fn_sig = tcx.fn_sig(def_id);
+        let fn_sig = tcx.fn_sig(def_id).subst_identity();
         let is_vtable_shim = !fn_sig.inputs().skip_binder().is_empty()
             && fn_sig.input(0).skip_binder().is_param(0)
             && tcx.generics_of(def_id).has_self;
@@ -756,14 +756,14 @@ fn needs_fn_once_adapter_shim(
             Ok(false)
         }
         (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
-            // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
+            // The closure fn `llfn` is a `fn(&self, ...)`. We want a
             // `fn(&mut self, ...)`. In fact, at codegen time, these are
             // basically the same thing, so we can just return llfn.
             Ok(false)
         }
         (ty::ClosureKind::Fn | ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
             // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
-            // self, ...)`.  We want a `fn(self, ...)`. We can produce
+            // self, ...)`. We want a `fn(self, ...)`. We can produce
             // this by doing something like:
             //
             //     fn call_once(self, ...) { call_mut(&self, ...) }
index 00f53afd6632854f824eb5df0d8256d61407ba18..cdcd6281f209bb4d25761ebb9e0a6cd9d1fac8f3 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"),
         }
     }
@@ -640,6 +645,7 @@ fn field_ty_or_layout<'tcx>(
                 | ty::Never
                 | ty::FnDef(..)
                 | ty::GeneratorWitness(..)
+                | ty::GeneratorWitnessMIR(..)
                 | ty::Foreign(..)
                 | ty::Dynamic(_, _, ty::Dyn) => {
                     bug!("TyAndLayout::field({:?}): not applicable", this)
@@ -812,132 +818,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 993e95b351484a7d31cb40dfc13a1d7414175633..25c6777a14c7084aa65ecdc7a933d66e78421056 100644 (file)
 pub use adt::*;
 pub use assoc::*;
 pub use generics::*;
-use hir::OpaqueTyOrigin;
 use rustc_ast as ast;
 use rustc_ast::node_id::NodeMap;
 use rustc_attr as attr;
-use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, LifetimeRes, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
 use rustc_hir::Node;
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
@@ -437,7 +435,7 @@ pub struct CrateVariancesMap<'tcx> {
     /// For each item with generics, maps to a vector of the variance
     /// of its generics. If an item has no generics, it will have no
     /// entry.
-    pub variances: FxHashMap<DefId, &'tcx [ty::Variance]>,
+    pub variances: DefIdMap<&'tcx [ty::Variance]>,
 }
 
 // Contains information needed to resolve types and (in the future) look up
@@ -454,18 +452,6 @@ pub struct CReaderCacheKey {
 #[rustc_pass_by_value]
 pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>);
 
-impl<'tcx> TyCtxt<'tcx> {
-    /// A "bool" type used in rustc_mir_transform unit tests when we
-    /// have not spun up a TyCtxt.
-    pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> =
-        Ty(Interned::new_unchecked(&WithCachedTypeInfo {
-            internee: ty::Bool,
-            stable_hash: Fingerprint::ZERO,
-            flags: TypeFlags::empty(),
-            outer_exclusive_binder: DebruijnIndex::from_usize(0),
-        }));
-}
-
 impl ty::EarlyBoundRegion {
     /// Does this early bound region have a name? Early bound regions normally
     /// always have names except when using anonymous lifetimes (`'_`).
@@ -689,7 +675,7 @@ pub fn subst_supertrait(
         //
         // In terms of why this is sound, the idea is that whenever there
         // is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>`
-        // holds.  So if there is an impl of `T:Foo<'a>` that applies to
+        // holds. So if there is an impl of `T:Foo<'a>` that applies to
         // all `'a`, then we must know that `T:Bar<'a,'a>` holds for all
         // `'a`.
         //
@@ -701,7 +687,7 @@ pub fn subst_supertrait(
         // Here, if we have `for<'x> T: Foo1<'x>`, then what do we know?
         // The answer is that we know `for<'x,'b> T: Bar1<'x,'b>`. The
         // reason is similar to the previous example: any impl of
-        // `T:Foo1<'x>` must show that `for<'b> T: Bar1<'x, 'b>`.  So
+        // `T:Foo1<'x>` must show that `for<'b> T: Bar1<'x, 'b>`. So
         // basically we would want to collapse the bound lifetimes from
         // the input (`trait_ref`) and the supertraits.
         //
@@ -1252,6 +1238,35 @@ pub fn empty() -> InstantiatedPredicates<'tcx> {
     pub fn is_empty(&self) -> bool {
         self.predicates.is_empty()
     }
+
+    pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter {
+        (&self).into_iter()
+    }
+}
+
+impl<'tcx> IntoIterator for InstantiatedPredicates<'tcx> {
+    type Item = (Predicate<'tcx>, Span);
+
+    type IntoIter = std::iter::Zip<std::vec::IntoIter<Predicate<'tcx>>, std::vec::IntoIter<Span>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        debug_assert_eq!(self.predicates.len(), self.spans.len());
+        std::iter::zip(self.predicates, self.spans)
+    }
+}
+
+impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> {
+    type Item = (Predicate<'tcx>, Span);
+
+    type IntoIter = std::iter::Zip<
+        std::iter::Copied<std::slice::Iter<'a, Predicate<'tcx>>>,
+        std::iter::Copied<std::slice::Iter<'a, Span>>,
+    >;
+
+    fn into_iter(self) -> Self::IntoIter {
+        debug_assert_eq!(self.predicates.len(), self.spans.len());
+        std::iter::zip(self.predicates.iter().copied(), self.spans.iter().copied())
+    }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable, Lift)]
@@ -1316,7 +1331,6 @@ pub fn remap_generic_params_to_declaration_params(
         tcx: TyCtxt<'tcx>,
         // typeck errors have subpar spans for opaque types, so delay error reporting until borrowck.
         ignore_errors: bool,
-        origin: OpaqueTyOrigin,
     ) -> Self {
         let OpaqueTypeKey { def_id, substs } = opaque_type_key;
 
@@ -1330,32 +1344,9 @@ pub fn remap_generic_params_to_declaration_params(
         debug!(?id_substs);
 
         // This zip may have several times the same lifetime in `substs` paired with a different
-        // lifetime from `id_substs`.  Simply `collect`ing the iterator is the correct behaviour:
+        // lifetime from `id_substs`. Simply `collect`ing the iterator is the correct behaviour:
         // it will pick the last one, which is the one we introduced in the impl-trait desugaring.
-        let map = substs.iter().zip(id_substs);
-
-        let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = match origin {
-            // HACK: The HIR lowering for async fn does not generate
-            // any `+ Captures<'x>` bounds for the `impl Future<...>`, so all async fns with lifetimes
-            // would now fail to compile. We should probably just make hir lowering fill this in properly.
-            OpaqueTyOrigin::AsyncFn(_) => map.collect(),
-            OpaqueTyOrigin::FnReturn(_) | OpaqueTyOrigin::TyAlias => {
-                // Opaque types may only use regions that are bound. So for
-                // ```rust
-                // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
-                // ```
-                // we may not use `'c` in the hidden type.
-                let variances = tcx.variances_of(def_id);
-                debug!(?variances);
-
-                map.filter(|(_, v)| {
-                    let ty::GenericArgKind::Lifetime(lt) = v.unpack() else { return true };
-                    let ty::ReEarlyBound(ebr) = lt.kind() else { bug!() };
-                    variances[ebr.index as usize] == ty::Variance::Invariant
-                })
-                .collect()
-            }
-        };
+        let map = substs.iter().zip(id_substs).collect();
         debug!("map = {:#?}", map);
 
         // Convert the type from the function into a type valid outside
@@ -2141,7 +2132,7 @@ pub fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
 
     /// Look up the name of a definition across crates. This does not look at HIR.
     ///
-    /// This method will ICE if the corresponding item does not have a name.  In these cases, use
+    /// This method will ICE if the corresponding item does not have a name. In these cases, use
     /// [`opt_item_name`] instead.
     ///
     /// [`opt_item_name`]: Self::opt_item_name
@@ -2187,8 +2178,10 @@ pub fn impls_are_allowed_to_overlap(
     ) -> Option<ImplOverlapKind> {
         // If either trait impl references an error, they're allowed to overlap,
         // as one of them essentially doesn't exist.
-        if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.references_error())
-            || self.impl_trait_ref(def_id2).map_or(false, |tr| tr.references_error())
+        if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.subst_identity().references_error())
+            || self
+                .impl_trait_ref(def_id2)
+                .map_or(false, |tr| tr.subst_identity().references_error())
         {
             return Some(ImplOverlapKind::Permitted { marker: false });
         }
@@ -2218,7 +2211,7 @@ pub fn impls_are_allowed_to_overlap(
         let is_marker_overlap = {
             let is_marker_impl = |def_id: DefId| -> bool {
                 let trait_ref = self.impl_trait_ref(def_id);
-                trait_ref.map_or(false, |tr| self.trait_def(tr.def_id).is_marker)
+                trait_ref.map_or(false, |tr| self.trait_def(tr.skip_binder().def_id).is_marker)
             };
             is_marker_impl(def_id1) && is_marker_impl(def_id2)
         };
@@ -2351,6 +2344,11 @@ pub fn trait_is_auto(self, trait_def_id: DefId) -> bool {
         self.trait_def(trait_def_id).has_auto_impl
     }
 
+    /// Returns `true` if this is a trait alias.
+    pub fn trait_is_alias(self, trait_def_id: DefId) -> bool {
+        self.def_kind(trait_def_id) == DefKind::TraitAlias
+    }
+
     pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool {
         self.trait_is_auto(trait_def_id) || self.lang_items().sized_trait() == Some(trait_def_id)
     }
@@ -2364,7 +2362,7 @@ pub fn generator_layout(self, def_id: DefId) -> Option<&'tcx GeneratorLayout<'tc
     /// Given the `DefId` of an impl, returns the `DefId` of the trait it implements.
     /// If it implements no trait, returns `None`.
     pub fn trait_id_of_impl(self, def_id: DefId) -> Option<DefId> {
-        self.impl_trait_ref(def_id).map(|tr| tr.def_id)
+        self.impl_trait_ref(def_id).map(|tr| tr.skip_binder().def_id)
     }
 
     /// If the given `DefId` describes an item belonging to a trait,
@@ -2426,6 +2424,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,
@@ -2459,10 +2458,6 @@ pub fn should_collapse_debuginfo(self, span: Span) -> bool {
             }
     }
 
-    pub fn is_object_safe(self, key: DefId) -> bool {
-        self.object_safety_violations(key).is_empty()
-    }
-
     #[inline]
     pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
         matches!(
@@ -2608,7 +2603,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 #[derive(Debug, Default, Copy, Clone)]
-pub struct FoundRelationships {
+pub struct InferVarInfo {
     /// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo`
     /// obligation, where:
     ///
index 98cd92007c2b22ace29115b466ce3f7fe0a75933..7ff58f02623dc1aa399f0c8cda4844a62f51d6b2 100644 (file)
@@ -3,6 +3,7 @@
 use crate::ty::subst::{GenericArg, GenericArgKind};
 use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_span::def_id::DefId;
 use rustc_span::Span;
 
 /// Converts generic params of a TypeFoldable from one
@@ -47,6 +48,47 @@ fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
         assert!(!self.do_not_error);
         kind.fold_with(self)
     }
+
+    fn fold_closure_substs(
+        &mut self,
+        def_id: DefId,
+        substs: ty::SubstsRef<'tcx>,
+    ) -> ty::SubstsRef<'tcx> {
+        // I am a horrible monster and I pray for death. When
+        // we encounter a closure here, it is always a closure
+        // from within the function that we are currently
+        // type-checking -- one that is now being encapsulated
+        // in an opaque type. Ideally, we would
+        // go through the types/lifetimes that it references
+        // and treat them just like we would any other type,
+        // which means we would error out if we find any
+        // reference to a type/region that is not in the
+        // "reverse map".
+        //
+        // **However,** in the case of closures, there is a
+        // somewhat subtle (read: hacky) consideration. The
+        // problem is that our closure types currently include
+        // all the lifetime parameters declared on the
+        // enclosing function, even if they are unused by the
+        // closure itself. We can't readily filter them out,
+        // so here we replace those values with `'empty`. This
+        // can't really make a difference to the rest of the
+        // compiler; those regions are ignored for the
+        // outlives relation, and hence don't affect trait
+        // selection or auto traits, and they are erased
+        // during codegen.
+
+        let generics = self.tcx.generics_of(def_id);
+        self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
+            if index < generics.parent_count {
+                // Accommodate missing regions in the parent kinds...
+                self.fold_kind_no_missing_regions_error(kind)
+            } else {
+                // ...but not elsewhere.
+                self.fold_kind_normally(kind)
+            }
+        }))
+    }
 }
 
 impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
@@ -104,59 +146,20 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         match *ty.kind() {
             ty::Closure(def_id, substs) => {
-                // I am a horrible monster and I pray for death. When
-                // we encounter a closure here, it is always a closure
-                // from within the function that we are currently
-                // type-checking -- one that is now being encapsulated
-                // in an opaque type. Ideally, we would
-                // go through the types/lifetimes that it references
-                // and treat them just like we would any other type,
-                // which means we would error out if we find any
-                // reference to a type/region that is not in the
-                // "reverse map".
-                //
-                // **However,** in the case of closures, there is a
-                // somewhat subtle (read: hacky) consideration. The
-                // problem is that our closure types currently include
-                // all the lifetime parameters declared on the
-                // enclosing function, even if they are unused by the
-                // closure itself. We can't readily filter them out,
-                // so here we replace those values with `'empty`. This
-                // can't really make a difference to the rest of the
-                // compiler; those regions are ignored for the
-                // outlives relation, and hence don't affect trait
-                // selection or auto traits, and they are erased
-                // during codegen.
-
-                let generics = self.tcx.generics_of(def_id);
-                let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
-                    if index < generics.parent_count {
-                        // Accommodate missing regions in the parent kinds...
-                        self.fold_kind_no_missing_regions_error(kind)
-                    } else {
-                        // ...but not elsewhere.
-                        self.fold_kind_normally(kind)
-                    }
-                }));
-
+                let substs = self.fold_closure_substs(def_id, substs);
                 self.tcx.mk_closure(def_id, substs)
             }
 
             ty::Generator(def_id, substs, movability) => {
-                let generics = self.tcx.generics_of(def_id);
-                let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
-                    if index < generics.parent_count {
-                        // Accommodate missing regions in the parent kinds...
-                        self.fold_kind_no_missing_regions_error(kind)
-                    } else {
-                        // ...but not elsewhere.
-                        self.fold_kind_normally(kind)
-                    }
-                }));
-
+                let substs = self.fold_closure_substs(def_id, substs);
                 self.tcx.mk_generator(def_id, substs, movability)
             }
 
+            ty::GeneratorWitnessMIR(def_id, substs) => {
+                let substs = self.fold_closure_substs(def_id, substs);
+                self.tcx.mk_generator_witness_mir(def_id, substs)
+            }
+
             ty::Param(param) => {
                 // Look it up in the substitution list.
                 match self.map.get(&ty.into()).map(|k| k.unpack()) {
index 72f451985796b82ac54a5809cf1f7dfd8dec9bd8..84edb5f2a4288fd4cfa12327c9504877866dd6f6 100644 (file)
@@ -32,6 +32,10 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> {
     type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>;
 }
 
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::EarlyBinder<T> {
+    type Value<'tcx> = ty::EarlyBinder<T::Value<'tcx>>;
+}
+
 #[macro_export]
 macro_rules! trivially_parameterized_over_tcx {
     ($($ty:ty),+ $(,)?) => {
@@ -48,6 +52,7 @@ impl $crate::ty::ParameterizedOverTcx for $ty {
     usize,
     (),
     u32,
+    bool,
     std::string::String,
     crate::metadata::ModChild,
     crate::middle::codegen_fn_attrs::CodegenFnAttrs,
@@ -112,6 +117,7 @@ impl $crate::ty::ParameterizedOverTcx for $($fake_path)::+<'static> {
 parameterized_over_tcx! {
     crate::middle::exported_symbols::ExportedSymbol,
     crate::mir::Body,
+    crate::mir::GeneratorLayout,
     ty::Ty,
     ty::FnSig,
     ty::GenericPredicates,
index 29bad33e4bc0f36aa5ef8f955e1ec30da54ef19a..90bf3288ccf5489946a63560ca32c066c30f5e6d 100644 (file)
@@ -116,7 +116,7 @@ fn default_print_def_path(
             DefPathData::Impl => {
                 let generics = self.tcx().generics_of(def_id);
                 let self_ty = self.tcx().bound_type_of(def_id);
-                let impl_trait_ref = self.tcx().bound_impl_trait_ref(def_id);
+                let impl_trait_ref = self.tcx().impl_trait_ref(def_id);
                 let (self_ty, impl_trait_ref) = if substs.len() >= generics.count() {
                     (
                         self_ty.subst(self.tcx(), substs),
@@ -265,6 +265,7 @@ fn characteristic_def_id_of_type_cached<'a>(
         ty::FnDef(def_id, _)
         | ty::Closure(def_id, _)
         | ty::Generator(def_id, _, _)
+        | ty::GeneratorWitnessMIR(def_id, _)
         | ty::Foreign(def_id) => Some(def_id),
 
         ty::Bool
index a91e8de5f21ea5221f33fccaa8b8b4392b46d178..f2abec216b7b371d594bd85f5a657fbca09e7f05 100644 (file)
@@ -393,7 +393,7 @@ fn try_print_trimmed_def_path(
         match self.tcx().trimmed_def_paths(()).get(&def_id) {
             None => Ok((self, false)),
             Some(symbol) => {
-                self.write_str(symbol.as_str())?;
+                write!(self, "{}", Ident::with_dummy_span(*symbol))?;
                 Ok((self, true))
             }
         }
@@ -675,7 +675,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                 p!(")")
             }
             ty::FnDef(def_id, substs) => {
-                let sig = self.tcx().bound_fn_sig(def_id).subst(self.tcx(), substs);
+                let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs);
                 p!(print(sig), " {{", print_value_path(def_id, substs), "}}");
             }
             ty::FnPtr(ref bare_fn) => p!(print(bare_fn)),
@@ -811,6 +811,28 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
             ty::GeneratorWitness(types) => {
                 p!(in_binder(&types));
             }
+            ty::GeneratorWitnessMIR(did, substs) => {
+                p!(write("["));
+                if !self.tcx().sess.verbose() {
+                    p!("generator witness");
+                    // FIXME(eddyb) should use `def_span`.
+                    if let Some(did) = did.as_local() {
+                        let span = self.tcx().def_span(did);
+                        p!(write(
+                            "@{}",
+                            // This may end up in stderr diagnostics but it may also be emitted
+                            // into MIR. Hence we use the remapped path if available
+                            self.tcx().sess.source_map().span_to_embeddable_string(span)
+                        ));
+                    } else {
+                        p!(write("@"), print_def_path(did, substs));
+                    }
+                } else {
+                    p!(print_def_path(did, substs));
+                }
+
+                p!("]")
+            }
             ty::Closure(did, substs) => {
                 p!(write("["));
                 if !self.should_print_verbose() {
@@ -854,24 +876,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                 }
                 p!("]");
             }
-            ty::Array(ty, sz) => {
-                p!("[", print(ty), "; ");
-                if self.should_print_verbose() {
-                    p!(write("{:?}", sz));
-                } else if let ty::ConstKind::Unevaluated(..) = sz.kind() {
-                    // Do not try to evaluate unevaluated constants. If we are const evaluating an
-                    // array length anon const, rustc will (with debug assertions) print the
-                    // constant's path. Which will end up here again.
-                    p!("_");
-                } else if let Some(n) = sz.kind().try_to_bits(self.tcx().data_layout.pointer_size) {
-                    p!(write("{}", n));
-                } else if let ty::ConstKind::Param(param) = sz.kind() {
-                    p!(print(param));
-                } else {
-                    p!("_");
-                }
-                p!("]")
-            }
+            ty::Array(ty, sz) => p!("[", print(ty), "; ", print(sz), "]"),
             ty::Slice(ty) => p!("[", print(ty), "]"),
         }
 
@@ -1303,21 +1308,25 @@ macro_rules! print_underscore {
         match ct.kind() {
             ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
                 match self.tcx().def_kind(def.did) {
-                    DefKind::Static(..) | DefKind::Const | DefKind::AssocConst => {
+                    DefKind::Const | DefKind::AssocConst => {
                         p!(print_value_path(def.did, substs))
                     }
-                    _ => {
-                        if def.is_local() {
-                            let span = self.tcx().def_span(def.did);
-                            if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
-                                p!(write("{}", snip))
-                            } else {
-                                print_underscore!()
-                            }
+                    DefKind::AnonConst => {
+                        if def.is_local()
+                            && let span = self.tcx().def_span(def.did)
+                            && let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)
+                        {
+                            p!(write("{}", snip))
                         } else {
-                            print_underscore!()
+                            // Do not call `print_value_path` as if a parent of this anon const is an impl it will
+                            // attempt to print out the impl trait ref i.e. `<T as Trait>::{constant#0}`. This would
+                            // cause printing to enter an infinite recursion if the anon const is in the self type i.e.
+                            // `impl<T: Default> Default for [T; 32 - 1 - 1 - 1] {`
+                            // where we would try to print `<[T; /* print `constant#0` again */] as Default>::{constant#0}`
+                            p!(write("{}::{}", self.tcx().crate_name(def.did.krate), self.tcx().def_path(def.did).to_string_no_crate_verbose()))
                         }
                     }
+                    defkind => bug!("`{:?}` has unexpcted defkind {:?}", ct, defkind),
                 }
             }
             ty::ConstKind::Infer(infer_ct) => {
@@ -1339,7 +1348,7 @@ macro_rules! print_underscore {
             ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
             // FIXME(generic_const_exprs):
             // write out some legible representation of an abstract const?
-            ty::ConstKind::Expr(_) => p!("[Const Expr]"),
+            ty::ConstKind::Expr(_) => p!("[const expr]"),
             ty::ConstKind::Error(_) => p!("[const error]"),
         };
         Ok(self)
@@ -2132,9 +2141,9 @@ pub fn pretty_print_region(mut self, region: ty::Region<'tcx>) -> Result<Self, f
 
         let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions;
 
-        // These printouts are concise.  They do not contain all the information
+        // These printouts are concise. They do not contain all the information
         // the user might want to diagnose an error, but there is basically no way
-        // to fit that into a short string.  Hence the recommendation to use
+        // to fit that into a short string. Hence the recommendation to use
         // `explain_region()` or `note_and_explain_region()`.
         match *region {
             ty::ReEarlyBound(ref data) => {
@@ -2481,7 +2490,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if not_previously_inserted {
                     ty.super_visit_with(self)
                 } else {
-                    ControlFlow::CONTINUE
+                    ControlFlow::Continue(())
                 }
             }
         }
index 9d4ee22a7273beba58c8cb282379a132a7585c03..1be819ca610c7c644f7b3c9c9325f4c52bf81494 100644 (file)
@@ -118,6 +118,7 @@ fn copy<T: Copy>(x: &T) -> T {
 
 macro_rules! query_helper_param_ty {
     (DefId) => { impl IntoQueryParam<DefId> };
+    (LocalDefId) => { impl IntoQueryParam<LocalDefId> };
     ($K:ty) => { $K };
 }
 
@@ -418,6 +419,13 @@ fn into_query_param(self) -> P {
         }
     }
 
+    impl IntoQueryParam<LocalDefId> for OwnerId {
+        #[inline(always)]
+        fn into_query_param(self) -> LocalDefId {
+            self.def_id
+        }
+    }
+
     impl IntoQueryParam<DefId> for LocalDefId {
         #[inline(always)]
         fn into_query_param(self) -> DefId {
@@ -441,6 +449,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 +461,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 65fd8d9753de18b7ad6982fe5124671803917d2b..fa87301df7e779f09d0eb8f002164b7fe9e82221 100644 (file)
@@ -443,12 +443,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             if a_repr == b_repr =>
         {
             let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
-                relation.relate_with_variance(
-                    ty::Contravariant,
-                    ty::VarianceDiagInfo::default(),
-                    a_region,
-                    b_region,
-                )
+                relation.relate(a_region, b_region)
             })?;
             Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr))
         }
@@ -473,6 +468,16 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             Ok(tcx.mk_generator_witness(types))
         }
 
+        (&ty::GeneratorWitnessMIR(a_id, a_substs), &ty::GeneratorWitnessMIR(b_id, b_substs))
+            if a_id == b_id =>
+        {
+            // All GeneratorWitness types with the same id represent
+            // the (anonymous) type of the same generator expression. So
+            // all of their regions should be equated.
+            let substs = relation.relate(a_substs, b_substs)?;
+            Ok(tcx.mk_generator_witness_mir(a_id, substs))
+        }
+
         (&ty::Closure(a_id, a_substs), &ty::Closure(b_id, b_substs)) if a_id == b_id => {
             // All Closure types with the same id represent
             // the (anonymous) type of the same closure expression. So
@@ -487,12 +492,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
         }
 
         (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
-            let r = relation.relate_with_variance(
-                ty::Contravariant,
-                ty::VarianceDiagInfo::default(),
-                a_r,
-                b_r,
-            )?;
+            let r = relation.relate(a_r, b_r)?;
             let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
             let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
             let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
index 30073b541ecbd0e5c09a32e0c91bcd028a6fa770..034aab0c38ea32a9a60d4be70d82bd37460c43a3 100644 (file)
@@ -7,10 +7,11 @@
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
 use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
+use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
 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;
@@ -180,6 +181,15 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+impl<'tcx> fmt::Debug for AliasTy<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("AliasTy")
+            .field("substs", &self.substs)
+            .field("def_id", &self.def_id)
+            .finish()
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // Atomic structs
 //
@@ -191,6 +201,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     bool,
     usize,
     ::rustc_target::abi::VariantIdx,
+    u16,
     u32,
     u64,
     String,
@@ -227,6 +238,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     crate::ty::BoundRegionKind,
     crate::ty::AssocItem,
     crate::ty::AssocKind,
+    crate::ty::AliasKind,
     crate::ty::Placeholder<crate::ty::BoundRegionKind>,
     crate::ty::ClosureKind,
     crate::ty::FreeRegion,
@@ -357,7 +369,7 @@ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<S
 
 impl<'tcx> TypeVisitable<'tcx> for ty::AdtDef<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 }
 
@@ -455,7 +467,7 @@ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
             let slot = Rc::get_mut_unchecked(&mut unique);
 
             // Semantically move the contained type out from `unique`, fold
-            // it, then move the folded value back into `unique`.  Should
+            // it, then move the folded value back into `unique`. Should
             // folding fail, `ManuallyDrop` ensures that the "moved-out"
             // value is not re-dropped.
             let owned = ManuallyDrop::take(slot);
@@ -501,7 +513,7 @@ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
             let slot = Arc::get_mut_unchecked(&mut unique);
 
             // Semantically move the contained type out from `unique`, fold
-            // it, then move the folded value back into `unique`.  Should
+            // it, then move the folded value back into `unique`. Should
             // folding fail, `ManuallyDrop` ensures that the "moved-out"
             // value is not re-dropped.
             let owned = ManuallyDrop::take(slot);
@@ -644,6 +656,9 @@ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
                 ty::Generator(did, substs.try_fold_with(folder)?, movability)
             }
             ty::GeneratorWitness(types) => ty::GeneratorWitness(types.try_fold_with(folder)?),
+            ty::GeneratorWitnessMIR(did, substs) => {
+                ty::GeneratorWitnessMIR(did, substs.try_fold_with(folder)?)
+            }
             ty::Closure(did, substs) => ty::Closure(did, substs.try_fold_with(folder)?),
             ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?),
 
@@ -689,6 +704,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow
             }
             ty::Generator(_did, ref substs, _) => substs.visit_with(visitor),
             ty::GeneratorWitness(ref types) => types.visit_with(visitor),
+            ty::GeneratorWitnessMIR(_did, ref substs) => substs.visit_with(visitor),
             ty::Closure(_did, ref substs) => substs.visit_with(visitor),
             ty::Alias(_, ref data) => data.visit_with(visitor),
 
@@ -704,7 +720,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow
             | ty::Placeholder(..)
             | ty::Param(..)
             | ty::Never
-            | ty::Foreign(..) => ControlFlow::CONTINUE,
+            | ty::Foreign(..) => ControlFlow::Continue(()),
         }
     }
 }
@@ -732,7 +748,7 @@ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
 
 impl<'tcx> TypeSuperVisitable<'tcx> for ty::Region<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 }
 
@@ -834,7 +850,7 @@ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<S
 
 impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 }
 
@@ -843,3 +859,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 bd5b04d5b2baac92b05047c271e24954d8817df8..f97d2e753a3b6d0ee1a5fb065b46d74cf7c26a0f 100644 (file)
@@ -7,8 +7,8 @@
 use crate::ty::visit::ValidateBoundVars;
 use crate::ty::InferTy::*;
 use crate::ty::{
-    self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
-    TypeVisitor,
+    self, AdtDef, DefIdTree, Discr, FallibleTypeFolder, Term, Ty, TyCtxt, TypeFlags, TypeFoldable,
+    TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 use crate::ty::{List, ParamEnv};
 use hir::def::DefKind;
@@ -100,6 +100,13 @@ pub fn get_name(&self) -> Option<Symbol> {
 
         None
     }
+
+    pub fn get_id(&self) -> Option<DefId> {
+        match *self {
+            BoundRegionKind::BrNamed(id, _) => return Some(id),
+            _ => None,
+        }
+    }
 }
 
 pub trait Article {
@@ -205,7 +212,7 @@ fn article(&self) -> &'static str {
 ///
 /// ## Generators
 ///
-/// Generators are handled similarly in `GeneratorSubsts`.  The set of
+/// Generators are handled similarly in `GeneratorSubsts`. The set of
 /// type parameters is similar, but `CK` and `CS` are replaced by the
 /// following type parameters:
 ///
@@ -564,9 +571,9 @@ pub fn state_tys(
     ) -> impl Iterator<Item = impl Iterator<Item = Ty<'tcx>> + Captures<'tcx>> {
         let layout = tcx.generator_layout(def_id).unwrap();
         layout.variant_fields.iter().map(move |variant| {
-            variant
-                .iter()
-                .map(move |field| ty::EarlyBinder(layout.field_tys[*field]).subst(tcx, self.substs))
+            variant.iter().map(move |field| {
+                ty::EarlyBinder(layout.field_tys[*field].ty).subst(tcx, self.substs)
+            })
         })
     }
 
@@ -1135,12 +1142,87 @@ pub fn iter(self) -> impl Iterator<Item = ty::Binder<'tcx, T::Item>> {
     }
 }
 
+struct SkipBindersAt<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    index: ty::DebruijnIndex,
+}
+
+impl<'tcx> FallibleTypeFolder<'tcx> for SkipBindersAt<'tcx> {
+    type Error = ();
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+    where
+        T: ty::TypeFoldable<'tcx>,
+    {
+        self.index.shift_in(1);
+        let value = t.try_map_bound(|t| t.try_fold_with(self));
+        self.index.shift_out(1);
+        value
+    }
+
+    fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+        if !ty.has_escaping_bound_vars() {
+            Ok(ty)
+        } else if let ty::Bound(index, bv) = *ty.kind() {
+            if index == self.index {
+                Err(())
+            } else {
+                Ok(self.tcx().mk_ty(ty::Bound(index.shifted_out(1), bv)))
+            }
+        } else {
+            ty.try_super_fold_with(self)
+        }
+    }
+
+    fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+        if !r.has_escaping_bound_vars() {
+            Ok(r)
+        } else if let ty::ReLateBound(index, bv) = r.kind() {
+            if index == self.index {
+                Err(())
+            } else {
+                Ok(self.tcx().mk_region(ty::ReLateBound(index.shifted_out(1), bv)))
+            }
+        } else {
+            r.try_super_fold_with(self)
+        }
+    }
+
+    fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
+        if !ct.has_escaping_bound_vars() {
+            Ok(ct)
+        } else if let ty::ConstKind::Bound(index, bv) = ct.kind() {
+            if index == self.index {
+                Err(())
+            } else {
+                Ok(self.tcx().mk_const(
+                    ty::ConstKind::Bound(index.shifted_out(1), bv),
+                    ct.ty().try_fold_with(self)?,
+                ))
+            }
+        } else {
+            ct.try_super_fold_with(self)
+        }
+    }
+
+    fn try_fold_predicate(
+        &mut self,
+        p: ty::Predicate<'tcx>,
+    ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+        if !p.has_escaping_bound_vars() { Ok(p) } else { p.try_super_fold_with(self) }
+    }
+}
+
 /// Represents the projection of an associated type.
 ///
 /// For a projection, this would be `<Ty as Trait<...>>::N`.
 ///
 /// For an opaque type, there is no explicit syntax.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct AliasTy<'tcx> {
     /// The parameters of the associated or opaque item.
@@ -1163,11 +1245,26 @@ pub struct AliasTy<'tcx> {
     /// aka. `tcx.parent(def_id)`.
     pub def_id: DefId,
 
-    /// This field exists to prevent the creation of `ProjectionTy` without using
+    /// This field exists to prevent the creation of `AliasTy` without using
     /// [TyCtxt::mk_alias_ty].
     pub(super) _use_mk_alias_ty_instead: (),
 }
 
+impl<'tcx> AliasTy<'tcx> {
+    pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind {
+        match tcx.def_kind(self.def_id) {
+            DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection,
+            DefKind::OpaqueTy => ty::Opaque,
+            kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
+        }
+    }
+
+    pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+        tcx.mk_ty(ty::Alias(self.kind(tcx), self))
+    }
+}
+
+/// The following methods work only with associated type projections.
 impl<'tcx> AliasTy<'tcx> {
     pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
         match tcx.def_kind(self.def_id) {
@@ -1175,7 +1272,7 @@ pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
             DefKind::ImplTraitPlaceholder => {
                 tcx.parent(tcx.impl_trait_in_trait_parent(self.def_id))
             }
-            kind => bug!("unexpected DefKind in ProjectionTy: {kind:?}"),
+            kind => bug!("expected a projection AliasTy; found {kind:?}"),
         }
     }
 
@@ -1929,7 +2026,7 @@ impl<'tcx> TypeVisitor<'tcx> for ContainsTyVisitor<'tcx> {
             type BreakTy = ();
 
             fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-                if self.0 == t { ControlFlow::BREAK } else { t.super_visit_with(self) }
+                if self.0 == t { ControlFlow::Break(()) } else { t.super_visit_with(self) }
             }
         }
 
@@ -1962,7 +2059,7 @@ pub fn builtin_index(self) -> Option<Ty<'tcx>> {
 
     pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
         match self.kind() {
-            FnDef(def_id, substs) => tcx.bound_fn_sig(*def_id).subst(tcx, substs),
+            FnDef(def_id, substs) => tcx.fn_sig(*def_id).subst(tcx, substs),
             FnPtr(f) => *f,
             Error(_) => {
                 // ignore errors (#54954)
@@ -2078,6 +2175,7 @@ pub fn discriminant_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
             | ty::Dynamic(..)
             | ty::Closure(..)
             | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..)
             | ty::Never
             | ty::Tuple(_)
             | ty::Error(_)
@@ -2113,6 +2211,7 @@ pub fn ptr_metadata_ty(
             | ty::Ref(..)
             | ty::Generator(..)
             | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..)
             | ty::Array(..)
             | ty::Closure(..)
             | ty::Never
@@ -2199,6 +2298,7 @@ pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
             | ty::Ref(..)
             | ty::Generator(..)
             | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..)
             | ty::Array(..)
             | ty::Closure(..)
             | ty::Never
@@ -2263,7 +2363,7 @@ pub fn is_trivially_pure_clone_copy(self) -> bool {
             // anything with custom metadata it might be more complicated.
             ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false,
 
-            ty::Generator(..) | ty::GeneratorWitness(..) => false,
+            ty::Generator(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => false,
 
             // Might be, but not "trivial" so just giving the safe answer.
             ty::Adt(..) | ty::Closure(..) => false,
index 2dec58ea82a30cbecb1c214e48a7047dd6a780e6..cf1bb5f8ac8db27900054ae4415777b520f93e52 100644 (file)
@@ -7,6 +7,7 @@
 use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
 
 use rustc_data_structures::intern::Interned;
+use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
 use rustc_serialize::{self, Decodable, Encodable};
@@ -36,6 +37,12 @@ pub struct GenericArg<'tcx> {
     marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>,
 }
 
+impl<'tcx> IntoDiagnosticArg for GenericArg<'tcx> {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        self.to_string().into_diagnostic_arg()
+    }
+}
+
 const TAG_MASK: usize = 0b11;
 const TYPE_TAG: usize = 0b00;
 const REGION_TAG: usize = 0b01;
@@ -538,6 +545,9 @@ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::Br
 /// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo<T>(T)`
 /// needs `T` substituted immediately. This type primarily exists to avoid forgetting to call
 /// `subst`.
+///
+/// If you don't have anything to `subst`, you may be looking for
+/// [`subst_identity`](EarlyBinder::subst_identity) or [`skip_binder`](EarlyBinder::skip_binder).
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 #[derive(Encodable, Decodable, HashStable)]
 pub struct EarlyBinder<T>(pub T);
@@ -578,6 +588,14 @@ pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> {
         EarlyBinder(value)
     }
 
+    /// Skips the binder and returns the "bound" value.
+    /// This can be used to extract data that does not depend on generic parameters
+    /// (e.g., getting the `DefId` of the inner value or getting the number of
+    /// arguments of an `FnSig`). Otherwise, consider using
+    /// [`subst_identity`](EarlyBinder::subst_identity).
+    ///
+    /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is
+    /// the analogous operation on [`super::Binder`].
     pub fn skip_binder(self) -> T {
         self.0
     }
@@ -639,6 +657,13 @@ fn next_back(&mut self) -> Option<Self::Item> {
     }
 }
 
+impl<'tcx, I: IntoIterator> ExactSizeIterator for SubstIter<'_, 'tcx, I>
+where
+    I::IntoIter: ExactSizeIterator,
+    I::Item: TypeFoldable<'tcx>,
+{
+}
+
 impl<'tcx, 's, I: IntoIterator> EarlyBinder<I>
 where
     I::Item: Deref,
@@ -686,6 +711,14 @@ fn next_back(&mut self) -> Option<Self::Item> {
     }
 }
 
+impl<'tcx, I: IntoIterator> ExactSizeIterator for SubstIterCopied<'_, 'tcx, I>
+where
+    I::IntoIter: ExactSizeIterator,
+    I::Item: Deref,
+    <I::Item as Deref>::Target: Copy + TypeFoldable<'tcx>,
+{
+}
+
 pub struct EarlyBinderIter<T> {
     t: T,
 }
@@ -713,6 +746,23 @@ pub fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> T {
         let mut folder = SubstFolder { tcx, substs, binders_passed: 0 };
         self.0.fold_with(&mut folder)
     }
+
+    /// Makes the identity substitution `T0 => T0, ..., TN => TN`.
+    /// Conceptually, this converts universally bound variables into placeholders
+    /// when inside of a given item.
+    ///
+    /// For example, consider `for<T> fn foo<T>(){ .. }`:
+    /// - Outside of `foo`, `T` is bound (represented by the presence of `EarlyBinder`).
+    /// - Inside of the body of `foo`, we treat `T` as a placeholder by calling
+    /// `subst_identity` to discharge the `EarlyBinder`.
+    pub fn subst_identity(self) -> T {
+        self.0
+    }
+
+    /// Returns the inner value, but only if it contains no bound vars.
+    pub fn no_bound_vars(self) -> Option<T> {
+        if !self.0.needs_subst() { Some(self.0) } else { None }
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
index 028a03c0b2bdd78d525892e8c5923289af1149e6..79a6c730d7159a5abcbf323ae029566c709952e6 100644 (file)
@@ -1,12 +1,18 @@
 use crate::{
     hir::place::Place as HirPlace,
     infer::canonical::Canonical,
+    traits::ObligationCause,
     ty::{
         self, tls, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData,
         GenericArgKind, InternalSubsts, SubstsRef, Ty, UserSubsts,
     },
 };
-use rustc_data_structures::{fx::FxHashMap, sync::Lrc, unord::UnordSet, vec_map::VecMap};
+use rustc_data_structures::{
+    fx::FxHashMap,
+    sync::Lrc,
+    unord::{UnordItems, UnordSet},
+    vec_map::VecMap,
+};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::{
 use rustc_middle::mir::FakeReadCause;
 use rustc_session::Session;
 use rustc_span::Span;
-use std::{
-    collections::hash_map::{self, Entry},
-    hash::Hash,
-    iter,
-};
+use std::{collections::hash_map::Entry, hash::Hash, iter};
 
 use super::RvalueScopes;
 
@@ -192,8 +194,13 @@ pub struct TypeckResults<'tcx> {
     /// that are live across the yield of this generator (if a generator).
     pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
 
+    /// Stores the predicates that apply on generator witness types.
+    /// formatting modified file tests/ui/generator/retain-resume-ref.rs
+    pub generator_interior_predicates:
+        FxHashMap<LocalDefId, Vec<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>>,
+
     /// We sometimes treat byte string literals (which are of type `&[u8; N]`)
-    /// as `&[u8]`, depending on the pattern  in which they are used.
+    /// as `&[u8]`, depending on the pattern in which they are used.
     /// This hashset records all instances where we behave
     /// like this to allow `const_to_pat` to reliably handle this situation.
     pub treat_byte_string_as_slice: ItemLocalSet,
@@ -270,6 +277,7 @@ pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> {
             closure_fake_reads: Default::default(),
             rvalue_scopes: Default::default(),
             generator_interior_types: ty::Binder::dummy(Default::default()),
+            generator_interior_predicates: Default::default(),
             treat_byte_string_as_slice: Default::default(),
             closure_size_eval: Default::default(),
         }
@@ -397,10 +405,10 @@ pub fn pat_ty(&self, pat: &hir::Pat<'_>) -> Ty<'tcx> {
 
     /// Returns the type of an expression as a monotype.
     ///
-    /// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression.  That is, in
+    /// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in
     /// some cases, we insert `Adjustment` annotations such as auto-deref or
-    /// auto-ref.  The type returned by this function does not consider such
-    /// adjustments.  See `expr_ty_adjusted()` instead.
+    /// auto-ref. The type returned by this function does not consider such
+    /// adjustments. See `expr_ty_adjusted()` instead.
     ///
     /// NB (2): This type doesn't provide type parameter substitutions; e.g., if you
     /// ask for the type of `id` in `id(3)`, it will return `fn(&isize) -> isize`
@@ -567,8 +575,15 @@ pub fn get(&self, id: hir::HirId) -> Option<&V> {
         self.data.get(&id.local_id)
     }
 
-    pub fn iter(&self) -> hash_map::Iter<'_, hir::ItemLocalId, V> {
-        self.data.iter()
+    pub fn items(
+        &'a self,
+    ) -> UnordItems<(hir::ItemLocalId, &'a V), impl Iterator<Item = (hir::ItemLocalId, &'a V)>>
+    {
+        self.data.items().map(|(id, value)| (*id, value))
+    }
+
+    pub fn items_in_stable_order(&self) -> Vec<(ItemLocalId, &'a V)> {
+        self.data.to_sorted_stable_ord()
     }
 }
 
@@ -605,6 +620,16 @@ pub fn remove(&mut self, id: hir::HirId) -> Option<V> {
         validate_hir_id_for_typeck_results(self.hir_owner, id);
         self.data.remove(&id.local_id)
     }
+
+    pub fn extend(
+        &mut self,
+        items: UnordItems<(hir::HirId, V), impl Iterator<Item = (hir::HirId, V)>>,
+    ) {
+        self.data.extend(items.map(|(id, value)| {
+            validate_hir_id_for_typeck_results(self.hir_owner, id);
+            (id.local_id, value)
+        }))
+    }
 }
 
 rustc_index::newtype_index! {
index cc53659f827986d7ff4b7a72163730bcb8a5f5eb..796164b0d6af39652c2f64f1f019b54267071a80 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,
@@ -616,6 +615,36 @@ pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> {
         }
     }
 
+    /// Return the set of types that should be taken into accound when checking
+    /// trait bounds on a generator's internal state.
+    pub fn generator_hidden_types(
+        self,
+        def_id: DefId,
+    ) -> impl Iterator<Item = ty::EarlyBinder<Ty<'tcx>>> {
+        let generator_layout = &self.mir_generator_witnesses(def_id);
+        generator_layout
+            .field_tys
+            .iter()
+            .filter(|decl| !decl.ignore_for_traits)
+            .map(|decl| ty::EarlyBinder(decl.ty))
+    }
+
+    /// Normalizes all opaque types in the given value, replacing them
+    /// with their underlying types.
+    pub fn expand_opaque_types(self, val: Ty<'tcx>) -> Ty<'tcx> {
+        let mut visitor = OpaqueTypeExpander {
+            seen_opaque_tys: FxHashSet::default(),
+            expanded_cache: FxHashMap::default(),
+            primary_def_id: None,
+            found_recursion: false,
+            found_any_recursion: false,
+            check_recursion: false,
+            expand_generators: false,
+            tcx: self,
+        };
+        val.fold_with(&mut visitor)
+    }
+
     /// Expands the given impl trait type, stopping if the type is recursive.
     #[instrument(skip(self), level = "debug", ret)]
     pub fn try_expand_impl_trait_type(
@@ -630,6 +659,7 @@ pub fn try_expand_impl_trait_type(
             found_recursion: false,
             found_any_recursion: false,
             check_recursion: true,
+            expand_generators: true,
             tcx: self,
         };
 
@@ -637,10 +667,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,
@@ -648,17 +674,6 @@ pub fn bound_return_position_impl_trait_in_trait_tys(
         ty::EarlyBinder(self.collect_return_position_impl_trait_in_trait_tys(def_id))
     }
 
-    pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {
-        ty::EarlyBinder(self.fn_sig(def_id))
-    }
-
-    pub fn bound_impl_trait_ref(
-        self,
-        def_id: DefId,
-    ) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
-        self.impl_trait_ref(def_id).map(|i| ty::EarlyBinder(i))
-    }
-
     pub fn bound_explicit_item_bounds(
         self,
         def_id: DefId,
@@ -666,31 +681,6 @@ pub fn bound_explicit_item_bounds(
         ty::EarlyBinder(self.explicit_item_bounds(def_id))
     }
 
-    pub fn bound_item_bounds(
-        self,
-        def_id: DefId,
-    ) -> ty::EarlyBinder<&'tcx ty::List<ty::Predicate<'tcx>>> {
-        ty::EarlyBinder(self.item_bounds(def_id))
-    }
-
-    pub fn bound_const_param_default(self, def_id: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
-        ty::EarlyBinder(self.const_param_default(def_id))
-    }
-
-    pub fn bound_predicates_of(
-        self,
-        def_id: DefId,
-    ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
-        ty::EarlyBinder(self.predicates_of(def_id))
-    }
-
-    pub fn bound_explicit_predicates_of(
-        self,
-        def_id: DefId,
-    ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
-        ty::EarlyBinder(self.explicit_predicates_of(def_id))
-    }
-
     pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder<ty::ImplSubject<'tcx>> {
         ty::EarlyBinder(self.impl_subject(def_id))
     }
@@ -770,12 +760,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
@@ -788,6 +772,7 @@ struct OpaqueTypeExpander<'tcx> {
     primary_def_id: Option<DefId>,
     found_recursion: bool,
     found_any_recursion: bool,
+    expand_generators: bool,
     /// Whether or not to check for recursive opaque types.
     /// This is `true` when we're explicitly checking for opaque type
     /// recursion, and 'false' otherwise to avoid unnecessary work.
@@ -824,6 +809,37 @@ fn expand_opaque_ty(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> Option
             None
         }
     }
+
+    fn expand_generator(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> Option<Ty<'tcx>> {
+        if self.found_any_recursion {
+            return None;
+        }
+        let substs = substs.fold_with(self);
+        if !self.check_recursion || self.seen_opaque_tys.insert(def_id) {
+            let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
+                Some(expanded_ty) => *expanded_ty,
+                None => {
+                    for bty in self.tcx.generator_hidden_types(def_id) {
+                        let hidden_ty = bty.subst(self.tcx, substs);
+                        self.fold_ty(hidden_ty);
+                    }
+                    let expanded_ty = self.tcx.mk_generator_witness_mir(def_id, substs);
+                    self.expanded_cache.insert((def_id, substs), expanded_ty);
+                    expanded_ty
+                }
+            };
+            if self.check_recursion {
+                self.seen_opaque_tys.remove(&def_id);
+            }
+            Some(expanded_ty)
+        } else {
+            // If another opaque type that we contain is recursive, then it
+            // will report the error, so we don't have to.
+            self.found_any_recursion = true;
+            self.found_recursion = def_id == *self.primary_def_id.as_ref().unwrap();
+            None
+        }
+    }
 }
 
 impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> {
@@ -832,13 +848,19 @@ fn tcx(&self) -> TyCtxt<'tcx> {
     }
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *t.kind() {
+        let mut t = if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *t.kind() {
             self.expand_opaque_ty(def_id, substs).unwrap_or(t)
-        } else if t.has_opaque_types() {
+        } else if t.has_opaque_types() || t.has_generators() {
             t.super_fold_with(self)
         } else {
             t
+        };
+        if self.expand_generators {
+            if let ty::GeneratorWitnessMIR(def_id, substs) = *t.kind() {
+                t = self.expand_generator(def_id, substs).unwrap_or(t);
+            }
         }
+        t
     }
 }
 
@@ -943,6 +965,7 @@ fn is_trivially_freeze(self) -> bool {
             | ty::Foreign(_)
             | ty::Generator(..)
             | ty::GeneratorWitness(_)
+            | ty::GeneratorWitnessMIR(..)
             | ty::Infer(_)
             | ty::Alias(..)
             | ty::Param(_)
@@ -982,6 +1005,7 @@ fn is_trivially_unpin(self) -> bool {
             | ty::Foreign(_)
             | ty::Generator(..)
             | ty::GeneratorWitness(_)
+            | ty::GeneratorWitnessMIR(..)
             | ty::Infer(_)
             | ty::Alias(..)
             | ty::Param(_)
@@ -1109,7 +1133,10 @@ pub fn is_structural_eq_shallow(self, tcx: TyCtxt<'tcx>) -> bool {
                 false
             }
 
-            ty::Foreign(_) | ty::GeneratorWitness(..) | ty::Error(_) => false,
+            ty::Foreign(_)
+            | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..)
+            | ty::Error(_) => false,
         }
     }
 
@@ -1205,6 +1232,7 @@ pub fn needs_drop_components<'tcx>(
         | ty::FnPtr(_)
         | ty::Char
         | ty::GeneratorWitness(..)
+        | ty::GeneratorWitnessMIR(..)
         | ty::RawPtr(_)
         | ty::Ref(..)
         | ty::Str => Ok(SmallVec::new()),
@@ -1275,7 +1303,11 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool {
 
         // Not trivial because they have components, and instead of looking inside,
         // we'll just perform trait selection.
-        ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(_) | ty::Adt(..) => false,
+        ty::Closure(..)
+        | ty::Generator(..)
+        | ty::GeneratorWitness(_)
+        | ty::GeneratorWitnessMIR(..)
+        | ty::Adt(..) => false,
 
         ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty),
 
@@ -1336,13 +1368,15 @@ pub fn reveal_opaque_types_in_bounds<'tcx>(
         found_recursion: false,
         found_any_recursion: false,
         check_recursion: false,
+        expand_generators: false,
         tcx,
     };
     val.fold_with(&mut visitor)
 }
 
 /// Determines whether an item is annotated with `doc(hidden)`.
-pub fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    assert!(def_id.is_local());
     tcx.get_attrs(def_id, sym::doc)
         .filter_map(|attr| attr.meta_item_list())
         .any(|items| items.iter().any(|item| item.has_name(sym::hidden)))
@@ -1357,7 +1391,7 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 
 /// Determines whether an item is an intrinsic by Abi.
 pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    matches!(tcx.fn_sig(def_id).abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic)
+    matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic)
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
index ca445558131380e364370ea518fb37a69a4c7bfa..d7b7a094737266e4d348a958b2f0b92cff7f708b 100644 (file)
@@ -100,6 +100,9 @@ fn has_projections(&self) -> bool {
     fn has_opaque_types(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
     }
+    fn has_generators(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_GENERATOR)
+    }
     fn references_error(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_ERROR)
     }
@@ -294,13 +297,13 @@ fn visit_binder<T: TypeVisitable<'tcx>>(
             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                 match *r {
                     ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => {
-                        ControlFlow::CONTINUE
+                        ControlFlow::Continue(())
                     }
                     _ => {
                         if (self.callback)(r) {
-                            ControlFlow::BREAK
+                            ControlFlow::Break(())
                         } else {
-                            ControlFlow::CONTINUE
+                            ControlFlow::Continue(())
                         }
                     }
                 }
@@ -311,7 +314,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
                     ty.super_visit_with(self)
                 } else {
-                    ControlFlow::CONTINUE
+                    ControlFlow::Continue(())
                 }
             }
         }
@@ -394,7 +397,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if t.outer_exclusive_binder() < self.binder_index
             || !self.visited.insert((self.binder_index, t))
         {
-            return ControlFlow::BREAK;
+            return ControlFlow::Break(());
         }
         match *t.kind() {
             ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
@@ -512,7 +515,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if t.outer_exclusive_binder() > self.outer_index {
             ControlFlow::Break(FoundEscapingVars)
         } else {
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         }
     }
 
@@ -524,7 +527,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         if r.bound_at_or_above_binder(self.outer_index) {
             ControlFlow::Break(FoundEscapingVars)
         } else {
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         }
     }
 
@@ -547,7 +550,7 @@ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Sel
         if predicate.outer_exclusive_binder() > self.outer_index {
             ControlFlow::Break(FoundEscapingVars)
         } else {
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         }
     }
 }
@@ -575,7 +578,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         }
     }
 
@@ -585,7 +588,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         if flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         }
     }
 
@@ -596,7 +599,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         if flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         }
     }
 
@@ -605,7 +608,7 @@ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Sel
         if predicate.flags().intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         }
     }
 }
@@ -653,7 +656,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         // in the normalized form
         if self.just_constrained {
             if let ty::Alias(..) = t.kind() {
-                return ControlFlow::CONTINUE;
+                return ControlFlow::Continue(());
             }
         }
 
@@ -666,7 +669,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         // in the normalized form
         if self.just_constrained {
             if let ty::ConstKind::Unevaluated(..) = c.kind() {
-                return ControlFlow::CONTINUE;
+                return ControlFlow::Continue(());
             }
         }
 
@@ -679,7 +682,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                 self.regions.insert(br.kind);
             }
         }
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 }
 
@@ -726,6 +729,6 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             );
         }
 
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 }
index 708a5e4d059e8acdab8166081f1c6c4d54fee151..182945b9c3db1ba01c210154cee3c1ecc015f0c6 100644 (file)
@@ -190,6 +190,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
             ty::Adt(_, substs)
             | ty::Closure(_, substs)
             | ty::Generator(_, substs, _)
+            | ty::GeneratorWitnessMIR(_, substs)
             | ty::FnDef(_, substs) => {
                 stack.extend(substs.iter().rev());
             }
index c242be570312354d780529f5df3449d0e6d64ffe..34e8a559784e6f021d3abd53b12271a0d8b74658 100644 (file)
@@ -94,6 +94,18 @@ fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
     }
 }
 
+impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
+        ty::EarlyBinder(Ty::from_cycle_error(tcx, cycle))
+    }
+}
+
+impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
+        ty::EarlyBinder(ty::Binder::from_cycle_error(tcx, cycle))
+    }
+}
+
 // item_and_field_ids should form a cycle where each field contains the
 // type in the next element in the list
 pub fn recursive_type_error(
index 34fefb99e09c25c1b034a2f431ce38dafbf3e39c..33fdc1901cd781b2832dbcdf832271ed706d5f8b 100644 (file)
@@ -86,10 +86,10 @@ pub(super) fn build_custom_mir<'tcx>(
         block_map: FxHashMap::default(),
     };
 
-    let res = (|| {
+    let res: PResult<_> = try {
         pctxt.parse_args(&params)?;
-        pctxt.parse_body(expr)
-    })();
+        pctxt.parse_body(expr)?;
+    };
     if let Err(err) = res {
         tcx.sess.diagnostic().span_fatal(
             err.span,
index dca4906c07de54bd2042edccd8ab65a5702e44fb..dbba529aef7a5ea6adbf1959bd923111b42db8fd 100644 (file)
 impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
     pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
         parse_by_kind!(self, expr_id, _, "statement",
+            @call("mir_storage_live", args) => {
+                Ok(StatementKind::StorageLive(self.parse_local(args[0])?))
+            },
+            @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])?)))
             },
@@ -135,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 dbcb0132c9f88f5993ca0c7920ba79ada3cb9d07..c621efb3b3a523e888da8f8670f926d19cb9d09c 100644 (file)
@@ -27,7 +27,7 @@ pub(crate) fn as_local_operand(
     /// suitable also to be passed as function arguments.
     ///
     /// The operand returned from this function will *not be valid* after an ExprKind::Scope is
-    /// passed, so please do *not* return it from functions to avoid bad miscompiles.  Returns an
+    /// passed, so please do *not* return it from functions to avoid bad miscompiles. Returns an
     /// operand suitable for use as a call argument. This is almost always equivalent to
     /// `as_operand`, except for the particular case of passing values of (potentially) unsized
     /// types "by value" (see details below).
index e9f327978aab1f0ac0617bafe6f3d85af4b31251..7808368519351b145df87a3b5f38b88f9a584f25 100644 (file)
@@ -57,7 +57,7 @@ pub(crate) fn stmt_expr(
                 // question raised here -- should we "freeze" the
                 // value of the lhs here?  I'm inclined to think not,
                 // since it seems closer to the semantics of the
-                // overloaded version, which takes `&mut self`.  This
+                // overloaded version, which takes `&mut self`. This
                 // only affects weird things like `x += {x += 1; x}`
                 // -- is that equal to `x + (x + 1)` or `2*(x+1)`?
 
@@ -113,7 +113,7 @@ pub(crate) fn stmt_expr(
                 //
                 // it is usually better to focus on `the_value` rather
                 // than the entirety of block(s) surrounding it.
-                let adjusted_span = (|| {
+                let adjusted_span =
                     if let ExprKind::Block { block } = expr.kind
                         && let Some(tail_ex) = this.thir[block].expr
                     {
@@ -135,10 +135,10 @@ pub(crate) fn stmt_expr(
                             tail_result_is_ignored: true,
                             span: expr.span,
                         });
-                        return Some(expr.span);
-                    }
-                    None
-                })();
+                        Some(expr.span)
+                    } else {
+                        None
+                    };
 
                 let temp =
                     unpack!(block = this.as_temp(block, statement_scope, expr, Mutability::Not));
index f90aba80bf3cf574f17fb3b0571cac22b5b4d6d2..6b960ebdb16f1291c4a6461049e9347e942daf17 100644 (file)
@@ -1747,8 +1747,10 @@ fn calculate_fake_borrows<'b>(
                 };
                 let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty;
                 let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
-                let fake_borrow_temp =
-                    self.local_decls.push(LocalDecl::new(fake_borrow_ty, temp_span));
+                let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span);
+                fake_borrow_temp.internal = self.local_decls[matched_place.local].internal;
+                fake_borrow_temp.local_info = Some(Box::new(LocalInfo::FakeBorrow));
+                let fake_borrow_temp = self.local_decls.push(fake_borrow_temp);
 
                 (matched_place, fake_borrow_temp)
             })
@@ -1870,7 +1872,7 @@ fn bind_and_guard_matched_candidate<'pat>(
         // ```
         // let place = Foo::new();
         // match place { foo if inspect(foo)
-        //     => feed(foo), ...  }
+        //     => feed(foo), ... }
         // ```
         //
         // will be treated as if it were really something like:
@@ -1885,7 +1887,7 @@ fn bind_and_guard_matched_candidate<'pat>(
         // ```
         // let place = Foo::new();
         // match place { ref mut foo if inspect(foo)
-        //     => feed(foo), ...  }
+        //     => feed(foo), ... }
         // ```
         //
         // will be treated as if it were really something like:
index 46e14cc9ac3b10667b9b5a5c2b19e9f40af71655..ad7a568a231814fcf8c7dbe9aed308eb125716f6 100644 (file)
@@ -456,7 +456,7 @@ fn non_scalar_compare(
                     span: source_info.span,
 
                     // FIXME(#54571): This constant comes from user input (a
-                    // constant in a pattern).  Are there forms where users can add
+                    // constant in a pattern). Are there forms where users can add
                     // type annotations here?  For example, an associated constant?
                     // Need to experiment.
                     user_ty: None,
@@ -504,7 +504,7 @@ fn non_scalar_compare(
     /// This is used by the overall `match_candidates` algorithm to structure
     /// the match as a whole. See `match_candidates` for more details.
     ///
-    /// FIXME(#29623). In some cases, we have some tricky choices to make.  for
+    /// FIXME(#29623). In some cases, we have some tricky choices to make. for
     /// example, if we are testing that `x == 22`, but the candidate is `x @
     /// 13..55`, what should we do? In the event that the test is true, we know
     /// that the candidate applies, but in the event of false, we don't know
index 9daf68a15f4b1ea4aef695c67f463e6f72514523..1655e224ddbb5b68f16f9710bdf509f18607d922 100644 (file)
@@ -439,6 +439,10 @@ fn construct_fn<'tcx>(
     let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def.did);
     let generator_kind = tcx.generator_kind(fn_def.did);
 
+    // The representation of thir for `-Zunpretty=thir-tree` relies on
+    // the entry expression being the last element of `thir.exprs`.
+    assert_eq!(expr.as_usize(), thir.exprs.len() - 1);
+
     // Figure out what primary body this item has.
     let body_id = tcx.hir().body_owned_by(fn_def.did);
     let span_with_body = tcx.hir().span_with_body(fn_id);
@@ -637,7 +641,7 @@ fn construct_error(
 
     let ty = tcx.ty_error();
     let num_params = match body_owner_kind {
-        hir::BodyOwnerKind::Fn => tcx.fn_sig(def).inputs().skip_binder().len(),
+        hir::BodyOwnerKind::Fn => tcx.fn_sig(def).skip_binder().inputs().skip_binder().len(),
         hir::BodyOwnerKind::Closure => {
             let ty = tcx.type_of(def);
             match ty.kind() {
index c92634a609de0f762df392231779f6510bc5a72e..591b416337b3595c36380af7d0197cccf9562086 100644 (file)
@@ -53,7 +53,7 @@
 ```
 
 When processing the `let x`, we will add one drop to the scope for
-`x`.  The break will then insert a drop for `x`. When we process `let
+`x`. The break will then insert a drop for `x`. When we process `let
 y`, we will add another drop (in fact, to a subscope, but let's ignore
 that for now); any later drops would also drop `y`.
 
@@ -757,7 +757,7 @@ pub(crate) fn maybe_new_source_scope(
             if self.tcx.sess.opts.unstable_opts.maximal_hir_to_mir_coverage {
                 // Some consumers of rustc need to map MIR locations back to HIR nodes. Currently the
                 // the only part of rustc that tracks MIR -> HIR is the `SourceScopeLocalData::lint_root`
-                // field that tracks lint levels for MIR locations.  Normally the number of source scopes
+                // field that tracks lint levels for MIR locations. Normally the number of source scopes
                 // is limited to the set of nodes with lint annotations. The -Zmaximal-hir-to-mir-coverage
                 // flag changes this behavior to maximize the number of source scopes, increasing the
                 // granularity of the MIR->HIR mapping.
index 06523b0a1de84cb658fc3e410bb4d61837eeeec9..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,
     },
 }
 
@@ -770,6 +794,8 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
     #[subdiagnostic]
     pub let_suggestion: Option<SuggestLet>,
     #[subdiagnostic]
+    pub misc_suggestion: Option<MiscPatternSuggestion>,
+    #[subdiagnostic]
     pub res_defined_here: Option<ResDefinedHere>,
 }
 
@@ -848,3 +874,16 @@ pub enum SuggestLet {
         count: usize,
     },
 }
+
+#[derive(Subdiagnostic)]
+pub enum MiscPatternSuggestion {
+    #[suggestion(
+        mir_build_suggest_attempted_int_lit,
+        code = "_",
+        applicability = "maybe-incorrect"
+    )]
+    AttemptedIntegerLiteral {
+        #[primary_span]
+        start_span: Span,
+    },
+}
index fb7ae6f1d242412e8e72197107f2214969a54e50..94dae36154c26181757616366db754e6412999b6 100644 (file)
@@ -5,7 +5,6 @@
 #![feature(assert_matches)]
 #![feature(associated_type_bounds)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(min_specialization)]
@@ -35,4 +34,5 @@ pub fn provide(providers: &mut Providers) {
     providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg;
     providers.thir_body = thir::cx::thir_body;
     providers.thir_tree = thir::cx::thir_tree;
+    providers.thir_flat = thir::cx::thir_flat;
 }
index 8529c64cd5cca64213f3b1efedb38df29c0094b5..f67f24b43c4d77f680053a394e8885760a69aaf3 100644 (file)
@@ -60,7 +60,7 @@ impl<'mir, 'tcx> Search<'mir, 'tcx> {
     /// Returns `true` if `func` refers to the function we are searching in.
     fn is_recursive_call(&self, func: &Operand<'tcx>, args: &[Operand<'tcx>]) -> bool {
         let Search { tcx, body, trait_substs, .. } = *self;
-        // Resolving function type to a specific instance that is being called is expensive.  To
+        // Resolving function type to a specific instance that is being called is expensive. To
         // avoid the cost we check the number of arguments first, which is sufficient to reject
         // most of calls as non-recursive.
         if args.len() != body.arg_count {
@@ -118,7 +118,7 @@ fn node_examined(
             // A diverging InlineAsm is treated as non-recursing
             TerminatorKind::InlineAsm { destination, .. } => {
                 if destination.is_some() {
-                    ControlFlow::CONTINUE
+                    ControlFlow::Continue(())
                 } else {
                     ControlFlow::Break(NonRecursive)
                 }
@@ -132,7 +132,7 @@ fn node_examined(
             | TerminatorKind::FalseEdge { .. }
             | TerminatorKind::FalseUnwind { .. }
             | TerminatorKind::Goto { .. }
-            | TerminatorKind::SwitchInt { .. } => ControlFlow::CONTINUE,
+            | TerminatorKind::SwitchInt { .. } => ControlFlow::Continue(()),
         }
     }
 
@@ -145,7 +145,7 @@ fn node_settled(&mut self, bb: BasicBlock) -> ControlFlow<Self::BreakVal> {
             }
         }
 
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 
     fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
index a355e1bdab5f51c78d865660833d0faafe83e33a..10df4b229520f3bd1f8f572353b994cb14ae273e 100644 (file)
@@ -53,6 +53,16 @@ pub(crate) fn thir_body(
 }
 
 pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
+    match thir_body(tcx, owner_def) {
+        Ok((thir, _)) => {
+            let thir = thir.steal();
+            tcx.thir_tree_representation(&thir)
+        }
+        Err(_) => "error".into(),
+    }
+}
+
+pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
     match thir_body(tcx, owner_def) {
         Ok((thir, _)) => format!("{:#?}", thir.steal()),
         Err(_) => "error".into(),
index e13c0662ef85f17cb45edb3bd2f7dd26820e7256..2640ca56b00e9764bdab912961dfa530798e3aac 100644 (file)
@@ -6,8 +6,9 @@
 
 use crate::errors::*;
 
+use hir::{ExprKind, PatKind};
 use rustc_arena::TypedArena;
-use rustc_ast::Mutability;
+use rustc_ast::{LitKind, Mutability};
 use rustc_errors::{
     struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
 };
@@ -207,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 => {}
@@ -389,7 +390,7 @@ fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>
             return;
         }
 
-        let (inform, interpreted_as_const, res_defined_here,let_suggestion) =
+        let (inform, interpreted_as_const, res_defined_here,let_suggestion, misc_suggestion) =
             if let hir::PatKind::Path(hir::QPath::Resolved(
                 None,
                 hir::Path {
@@ -413,6 +414,7 @@ fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>
                         }
                     },
                     None,
+                    None,
                 )
             } else if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) {
                 let mut bindings = vec![];
@@ -426,10 +428,19 @@ fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>
                 let end_span = semi_span.shrink_to_lo();
                 let count = witnesses.len();
 
+                // If the pattern to match is an integer literal:
+                let int_suggestion = if
+                    let PatKind::Lit(expr) = &pat.kind
+                    && bindings.is_empty()
+                    && let ExprKind::Lit(Spanned { node: LitKind::Int(_, _), span }) = expr.kind {
+                    // Then give a suggestion, the user might've meant to create a binding instead.
+                    Some(MiscPatternSuggestion::AttemptedIntegerLiteral { start_span: span.shrink_to_lo() })
+                } else { None };
+
                 let let_suggestion = if bindings.is_empty() {SuggestLet::If{start_span, semi_span, count}} else{ SuggestLet::Else{end_span, count }};
-                (sp.map(|_|Inform), None, None, Some(let_suggestion))
+                (sp.map(|_|Inform), None, None, Some(let_suggestion), int_suggestion)
             } else{
-                (sp.map(|_|Inform), None, None,  None)
+                (sp.map(|_|Inform), None, None,  None, None)
             };
 
         let adt_defined_here = try {
@@ -453,6 +464,7 @@ fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>
             _p: (),
             pattern_ty,
             let_suggestion,
+            misc_suggestion,
             res_defined_here,
             adt_defined_here,
         });
@@ -914,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..ff88d00135173ec90be84ffdef34170ea2d1f005 100644 (file)
@@ -192,7 +192,7 @@ fn type_may_have_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
         let obligation: PredicateObligation<'_> = predicate_for_trait_def(
             self.tcx(),
             self.param_env,
-            ObligationCause::misc(self.span, self.id),
+            ObligationCause::misc(self.span, self.id.owner.def_id),
             partial_eq_trait_id,
             0,
             [ty, ty],
index 17b3c475f83c78a3d4711e65092859da5d5d147b..aba5429da435f84292cb698a9e62d7d6b53b61ba 100644 (file)
@@ -141,27 +141,22 @@ fn from_constant<'tcx>(
     ) -> Option<IntRange> {
         let ty = value.ty();
         if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) {
-            let val = (|| {
-                match value {
-                    mir::ConstantKind::Val(ConstValue::Scalar(scalar), _) => {
-                        // For this specific pattern we can skip a lot of effort and go
-                        // straight to the result, after doing a bit of checking. (We
-                        // could remove this branch and just fall through, which
-                        // is more general but much slower.)
-                        return scalar.to_bits_or_ptr_internal(target_size).unwrap().left();
-                    }
-                    mir::ConstantKind::Ty(c) => match c.kind() {
-                        ty::ConstKind::Value(_) => bug!(
-                            "encountered ConstValue in mir::ConstantKind::Ty, whereas this is expected to be in ConstantKind::Val"
-                        ),
-                        _ => {}
-                    },
-                    _ => {}
+            let val = if let mir::ConstantKind::Val(ConstValue::Scalar(scalar), _) = value {
+                // For this specific pattern we can skip a lot of effort and go
+                // straight to the result, after doing a bit of checking. (We
+                // could remove this branch and just fall through, which
+                // is more general but much slower.)
+                scalar.to_bits_or_ptr_internal(target_size).unwrap().left()?
+            } else {
+                if let mir::ConstantKind::Ty(c) = value
+                    && let ty::ConstKind::Value(_) = c.kind()
+                {
+                    bug!("encountered ConstValue in mir::ConstantKind::Ty, whereas this is expected to be in ConstantKind::Val");
                 }
 
                 // This is a more general form of the previous case.
-                value.try_eval_bits(tcx, param_env, ty)
-            })()?;
+                value.try_eval_bits(tcx, param_env, ty)?
+            };
             let val = val ^ bias;
             Some(IntRange { range: val..=val, bias })
         } else {
index 923dc16c11b077268e175de33677bb58400649c3..2890fa32cc915fdf540f2ee66ce73d7afc44c31b 100644 (file)
@@ -271,6 +271,7 @@ fn apply_statement_effect(
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => None,
         };
         if let Some(destination) = destination {
index bc31ec42b8b6e3af8e6b3dc4f2c13e9b646a8d37..4b5324e203aa3725aad358ad587e2eb714b366b1 100644 (file)
@@ -750,7 +750,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'_>, location: Location) {
 
 /// Calls `f` for each mutable borrow or raw reference in the program.
 ///
-/// This DOES NOT call `f` for a shared borrow of a type with interior mutability.  That's okay for
+/// This DOES NOT call `f` for a shared borrow of a type with interior mutability. That's okay for
 /// initializedness, because we cannot move from an `UnsafeCell` (outside of `core::cell`), but
 /// other analyses will likely need to check for `!Freeze`.
 fn for_each_mut_borrow<'tcx>(
index 8d379b90a86db28194b2946df68bc564b8e84961..fcf0ce9d82118815eadbb0229be5bac3e49afe21 100644 (file)
@@ -141,6 +141,7 @@ fn before_statement_effect(
             StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
             | StatementKind::FakeRead(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop
             | StatementKind::Retag(..)
             | StatementKind::Intrinsic(..)
index f46fd118bde5d165106bfcb047dd7d2d5f494232..0195693a7cb0e6d9bf8639e83d8e96a5b59797a3 100644 (file)
@@ -331,6 +331,7 @@ fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
         }
     }
index 0522c657939f5e100c7827dd319862ce3eedaf09..6bdbda909d7bdf02da963730db84fa2a3d2be991 100644 (file)
@@ -84,7 +84,8 @@ fn super_statement(&self, statement: &Statement<'tcx>, state: &mut State<Self::V
             StatementKind::Retag(..) => {
                 // We don't track references.
             }
-            StatementKind::Nop
+            StatementKind::ConstEvalCounter
+            | StatementKind::Nop
             | StatementKind::FakeRead(..)
             | StatementKind::Coverage(..)
             | StatementKind::AscribeUserType(..) => (),
index 3d22035f0785ed57509c86c251355156d92d3665..7d2146214c6dc2128040b12ab248e32272d1b016 100644 (file)
@@ -120,7 +120,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // PART 3
         // Add retag after assignments where data "enters" this function: the RHS is behind a deref and the LHS is not.
         for block_data in basic_blocks {
-            // We want to insert statements as we iterate.  To this end, we
+            // We want to insert statements as we iterate. To this end, we
             // iterate backwards using indices.
             for i in (0..block_data.statements.len()).rev() {
                 let (retag_kind, place) = match block_data.statements[i].kind {
index adf6ae4c7270fbe37b642bb26e738d7cb1063354..8afa53313fc2840e838cc13e8d5d4170a3151de3 100644 (file)
@@ -104,6 +104,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {
                 // safe (at least as emitted during MIR construction)
             }
@@ -445,7 +446,7 @@ fn visit_fn(
         _fd: &'tcx hir::FnDecl<'tcx>,
         b: hir::BodyId,
         _s: rustc_span::Span,
-        _id: HirId,
+        _id: LocalDefId,
     ) {
         if matches!(fk, intravisit::FnKind::Closure) {
             self.visit_body(self.tcx.hir().body(b))
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()?;
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
new file mode 100644 (file)
index 0000000..182b301
--- /dev/null
@@ -0,0 +1,178 @@
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::impls::borrowed_locals;
+
+use crate::ssa::SsaLocals;
+use crate::MirPass;
+
+/// Unify locals that copy each other.
+///
+/// We consider patterns of the form
+///   _a = rvalue
+///   _b = move? _a
+///   _c = move? _a
+///   _d = move? _c
+/// where each of the locals is only assigned once.
+///
+/// We want to replace all those locals by `_a`, either copied or moved.
+pub struct CopyProp;
+
+impl<'tcx> MirPass<'tcx> for CopyProp {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() >= 4
+    }
+
+    #[instrument(level = "trace", skip(self, tcx, body))]
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        debug!(def_id = ?body.source.def_id());
+        propagate_ssa(tcx, body);
+    }
+}
+
+fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+    let borrowed_locals = borrowed_locals(body);
+    let ssa = SsaLocals::new(tcx, param_env, body, &borrowed_locals);
+
+    let fully_moved = fully_moved_locals(&ssa, body);
+    debug!(?fully_moved);
+
+    let mut storage_to_remove = BitSet::new_empty(fully_moved.domain_size());
+    for (local, &head) in ssa.copy_classes().iter_enumerated() {
+        if local != head {
+            storage_to_remove.insert(head);
+        }
+    }
+
+    let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h);
+
+    Replacer {
+        tcx,
+        copy_classes: &ssa.copy_classes(),
+        fully_moved,
+        borrowed_locals,
+        storage_to_remove,
+    }
+    .visit_body_preserves_cfg(body);
+
+    if any_replacement {
+        crate::simplify::remove_unused_definitions(body);
+    }
+}
+
+/// `SsaLocals` computed equivalence classes between locals considering copy/move assignments.
+///
+/// This function also returns whether all the `move?` in the pattern are `move` and not copies.
+/// A local which is in the bitset can be replaced by `move _a`. Otherwise, it must be
+/// replaced by `copy _a`, as we cannot move multiple times from `_a`.
+///
+/// If an operand copies `_c`, it must happen before the assignment `_d = _c`, otherwise it is UB.
+/// This means that replacing it by a copy of `_a` if ok, since this copy happens before `_c` is
+/// moved, and therefore that `_d` is moved.
+#[instrument(level = "trace", skip(ssa, body))]
+fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet<Local> {
+    let mut fully_moved = BitSet::new_filled(body.local_decls.len());
+
+    for (_, rvalue) in ssa.assignments(body) {
+        let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place))
+            = rvalue
+        else { continue };
+
+        let Some(rhs) = place.as_local() else { continue };
+        if !ssa.is_ssa(rhs) {
+            continue;
+        }
+
+        if let Rvalue::Use(Operand::Copy(_)) | Rvalue::CopyForDeref(_) = rvalue {
+            fully_moved.remove(rhs);
+        }
+    }
+
+    ssa.meet_copy_equivalence(&mut fully_moved);
+
+    fully_moved
+}
+
+/// Utility to help performing subtitution of `*pattern` by `target`.
+struct Replacer<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    fully_moved: BitSet<Local>,
+    storage_to_remove: BitSet<Local>,
+    borrowed_locals: BitSet<Local>,
+    copy_classes: &'a IndexVec<Local, Local>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn visit_local(&mut self, local: &mut Local, ctxt: PlaceContext, _: Location) {
+        let new_local = self.copy_classes[*local];
+        match ctxt {
+            // Do not modify the local in storage statements.
+            PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => {}
+            // The local should have been marked as non-SSA.
+            PlaceContext::MutatingUse(_) => assert_eq!(*local, new_local),
+            // We access the value.
+            _ => *local = new_local,
+        }
+    }
+
+    fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
+        if let Some(new_projection) = self.process_projection(&place.projection, loc) {
+            place.projection = self.tcx().intern_place_elems(&new_projection);
+        }
+
+        let observes_address = match ctxt {
+            PlaceContext::NonMutatingUse(
+                NonMutatingUseContext::SharedBorrow
+                | NonMutatingUseContext::ShallowBorrow
+                | NonMutatingUseContext::UniqueBorrow
+                | NonMutatingUseContext::AddressOf,
+            ) => true,
+            // For debuginfo, merging locals is ok.
+            PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {
+                self.borrowed_locals.contains(place.local)
+            }
+            _ => false,
+        };
+        if observes_address && !place.is_indirect() {
+            // We observe the address of `place.local`. Do not replace it.
+        } else {
+            self.visit_local(
+                &mut place.local,
+                PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
+                loc,
+            )
+        }
+    }
+
+    fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
+        if let Operand::Move(place) = *operand
+            && let Some(local) = place.as_local()
+            && !self.fully_moved.contains(local)
+        {
+            *operand = Operand::Copy(place);
+        }
+        self.super_operand(operand, loc);
+    }
+
+    fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, loc: Location) {
+        if let StatementKind::StorageDead(l) = stmt.kind
+            && self.storage_to_remove.contains(l)
+        {
+            stmt.make_nop();
+        } else if let StatementKind::Assign(box (ref place, ref mut rvalue)) = stmt.kind
+            && place.as_local().is_some()
+        {
+            // Do not replace assignments.
+            self.visit_rvalue(rvalue, loc)
+        } else {
+            self.super_statement(stmt, loc);
+        }
+    }
+}
index 45de0c280352f83341cfc65cb6aaac9540aaa35c..658e01d9310317d4bf955b528a0b662d3b1eb6a3 100644 (file)
@@ -520,7 +520,7 @@ fn find_some_reloop_branch(
                 let mut found_loop_exit = false;
                 for &branch in branches.iter() {
                     if backedge_from_bcbs.iter().any(|&backedge_from_bcb| {
-                        self.bcb_is_dominated_by(backedge_from_bcb, branch.target_bcb)
+                        self.bcb_dominates(branch.target_bcb, backedge_from_bcb)
                     }) {
                         if let Some(reloop_branch) = some_reloop_branch {
                             if reloop_branch.counter(&self.basic_coverage_blocks).is_none() {
@@ -603,8 +603,8 @@ fn bcb_has_one_path_to_target(&self, bcb: BasicCoverageBlock) -> bool {
     }
 
     #[inline]
-    fn bcb_is_dominated_by(&self, node: BasicCoverageBlock, dom: BasicCoverageBlock) -> bool {
-        self.basic_coverage_blocks.is_dominated_by(node, dom)
+    fn bcb_dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool {
+        self.basic_coverage_blocks.dominates(dom, node)
     }
 
     #[inline]
index 78d28f1ebab7ce345d5082169bb0b80e4c34045b..a2671eef2e940ef09ae4170ee8deea7b3298cf60 100644 (file)
@@ -209,8 +209,8 @@ pub fn bcb_from_bb(&self, bb: BasicBlock) -> Option<BasicCoverageBlock> {
     }
 
     #[inline(always)]
-    pub fn is_dominated_by(&self, node: BasicCoverageBlock, dom: BasicCoverageBlock) -> bool {
-        self.dominators.as_ref().unwrap().is_dominated_by(node, dom)
+    pub fn dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool {
+        self.dominators.as_ref().unwrap().dominates(dom, node)
     }
 
     #[inline(always)]
@@ -312,7 +312,7 @@ pub(super) struct BasicCoverageBlock {
 /// to the BCB's primary counter or expression).
 ///
 /// The BCB CFG is critical to simplifying the coverage analysis by ensuring graph path-based
-/// queries (`is_dominated_by()`, `predecessors`, `successors`, etc.) have branch (control flow)
+/// queries (`dominates()`, `predecessors`, `successors`, etc.) have branch (control flow)
 /// significance.
 #[derive(Debug, Clone)]
 pub(super) struct BasicCoverageBlockData {
@@ -594,7 +594,7 @@ pub fn extend_worklist(
                 // branching block would have given an `Expression` (or vice versa).
                 let (some_successor_to_add, some_loop_header) =
                     if let Some((_, loop_header)) = context.loop_backedges {
-                        if basic_coverage_blocks.is_dominated_by(successor, loop_header) {
+                        if basic_coverage_blocks.dominates(loop_header, successor) {
                             (Some(successor), Some(loop_header))
                         } else {
                             (None, None)
@@ -666,15 +666,15 @@ pub(super) fn find_loop_backedges(
     //
     // The overall complexity appears to be comparable to many other MIR transform algorithms, and I
     // don't expect that this function is creating a performance hot spot, but if this becomes an
-    // issue, there may be ways to optimize the `is_dominated_by` algorithm (as indicated by an
+    // issue, there may be ways to optimize the `dominates` algorithm (as indicated by an
     // existing `FIXME` comment in that code), or possibly ways to optimize it's usage here, perhaps
     // by keeping track of results for visited `BasicCoverageBlock`s if they can be used to short
-    // circuit downstream `is_dominated_by` checks.
+    // circuit downstream `dominates` checks.
     //
     // For now, that kind of optimization seems unnecessarily complicated.
     for (bcb, _) in basic_coverage_blocks.iter_enumerated() {
         for &successor in &basic_coverage_blocks.successors[bcb] {
-            if basic_coverage_blocks.is_dominated_by(bcb, successor) {
+            if basic_coverage_blocks.dominates(successor, bcb) {
                 let loop_header = successor;
                 let backedge_from_bcb = bcb;
                 debug!(
index 1468afc64563dc20bba1ea5e4e2f062918042d99..9a617159813caeca77f5342ffebcf714a5b9643b 100644 (file)
@@ -540,7 +540,8 @@ fn fn_sig_and_body(
     // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back
     // to HIR for it.
     let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
-    let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body");
+    let (_, fn_body_id) =
+        hir::map::associated_body(hir_node).expect("HIR node is a function with body");
     (hir_node.fn_sig(), tcx.hir().body(fn_body_id))
 }
 
index 9f842c929dc2478034f6962b05a8c4b63ac05419..f973c1ed28f4a639b7bd17351a76f6ace8f34499 100644 (file)
@@ -63,7 +63,7 @@ pub fn span(&self) -> Span {
 /// Note: A `CoverageStatement` merged into another CoverageSpan may come from a `BasicBlock` that
 /// is not part of the `CoverageSpan` bcb if the statement was included because it's `Span` matches
 /// or is subsumed by the `Span` associated with this `CoverageSpan`, and it's `BasicBlock`
-/// `is_dominated_by()` the `BasicBlock`s in this `CoverageSpan`.
+/// `dominates()` the `BasicBlock`s in this `CoverageSpan`.
 #[derive(Debug, Clone)]
 pub(super) struct CoverageSpan {
     pub span: Span,
@@ -341,11 +341,11 @@ fn mir_to_initial_sorted_coverage_spans(&self) -> Vec<CoverageSpan> {
                     if a.is_in_same_bcb(b) {
                         Some(Ordering::Equal)
                     } else {
-                        // Sort equal spans by dominator relationship, in reverse order (so
-                        // dominators always come after the dominated equal spans). When later
-                        // comparing two spans in order, the first will either dominate the second,
-                        // or they will have no dominator relationship.
-                        self.basic_coverage_blocks.dominators().rank_partial_cmp(b.bcb, a.bcb)
+                        // Sort equal spans by dominator relationship (so dominators always come
+                        // before the dominated equal spans). When later comparing two spans in
+                        // order, the first will either dominate the second, or they will have no
+                        // dominator relationship.
+                        self.basic_coverage_blocks.dominators().rank_partial_cmp(a.bcb, b.bcb)
                     }
                 } else {
                     // Sort hi() in reverse order so shorter spans are attempted after longer spans.
@@ -705,12 +705,12 @@ fn carve_out_span_for_closure(&mut self) {
     fn hold_pending_dups_unless_dominated(&mut self) {
         // Equal coverage spans are ordered by dominators before dominated (if any), so it should be
         // impossible for `curr` to dominate any previous `CoverageSpan`.
-        debug_assert!(!self.span_bcb_is_dominated_by(self.prev(), self.curr()));
+        debug_assert!(!self.span_bcb_dominates(self.curr(), self.prev()));
 
         let initial_pending_count = self.pending_dups.len();
         if initial_pending_count > 0 {
             let mut pending_dups = self.pending_dups.split_off(0);
-            pending_dups.retain(|dup| !self.span_bcb_is_dominated_by(self.curr(), dup));
+            pending_dups.retain(|dup| !self.span_bcb_dominates(dup, self.curr()));
             self.pending_dups.append(&mut pending_dups);
             if self.pending_dups.len() < initial_pending_count {
                 debug!(
@@ -721,7 +721,7 @@ fn hold_pending_dups_unless_dominated(&mut self) {
             }
         }
 
-        if self.span_bcb_is_dominated_by(self.curr(), self.prev()) {
+        if self.span_bcb_dominates(self.prev(), self.curr()) {
             debug!(
                 "  different bcbs but SAME spans, and prev dominates curr. Discard prev={:?}",
                 self.prev()
@@ -787,8 +787,8 @@ fn cutoff_prev_at_overlapping_curr(&mut self) {
         }
     }
 
-    fn span_bcb_is_dominated_by(&self, covspan: &CoverageSpan, dom_covspan: &CoverageSpan) -> bool {
-        self.basic_coverage_blocks.is_dominated_by(covspan.bcb, dom_covspan.bcb)
+    fn span_bcb_dominates(&self, dom_covspan: &CoverageSpan, covspan: &CoverageSpan) -> bool {
+        self.basic_coverage_blocks.dominates(dom_covspan.bcb, covspan.bcb)
     }
 }
 
@@ -802,6 +802,8 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span>
         | StatementKind::StorageDead(_)
         // Coverage should not be encountered, but don't inject coverage coverage
         | StatementKind::Coverage(_)
+        // Ignore `ConstEvalCounter`s
+        | StatementKind::ConstEvalCounter
         // Ignore `Nop`s
         | StatementKind::Nop => None,
 
diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs
new file mode 100644 (file)
index 0000000..7d12703
--- /dev/null
@@ -0,0 +1,59 @@
+//! A pass that inserts the `ConstEvalCounter` instruction into any blocks that have a back edge
+//! (thus indicating there is a loop in the CFG), or whose terminator is a function call.
+use crate::MirPass;
+
+use rustc_data_structures::graph::dominators::Dominators;
+use rustc_middle::mir::{
+    BasicBlock, BasicBlockData, Body, Statement, StatementKind, TerminatorKind,
+};
+use rustc_middle::ty::TyCtxt;
+
+pub struct CtfeLimit;
+
+impl<'tcx> MirPass<'tcx> for CtfeLimit {
+    #[instrument(skip(self, _tcx, body))]
+    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let doms = body.basic_blocks.dominators();
+        let indices: Vec<BasicBlock> = body
+            .basic_blocks
+            .iter_enumerated()
+            .filter_map(|(node, node_data)| {
+                if matches!(node_data.terminator().kind, TerminatorKind::Call { .. })
+                    // Back edges in a CFG indicate loops
+                    || has_back_edge(&doms, node, &node_data)
+                {
+                    Some(node)
+                } else {
+                    None
+                }
+            })
+            .collect();
+        for index in indices {
+            insert_counter(
+                body.basic_blocks_mut()
+                    .get_mut(index)
+                    .expect("basic_blocks index {index} should exist"),
+            );
+        }
+    }
+}
+
+fn has_back_edge(
+    doms: &Dominators<BasicBlock>,
+    node: BasicBlock,
+    node_data: &BasicBlockData<'_>,
+) -> bool {
+    if !doms.is_reachable(node) {
+        return false;
+    }
+    // Check if any of the dominators of the node are also the node's successor.
+    doms.dominators(node)
+        .any(|dom| node_data.terminator().successors().into_iter().any(|succ| succ == dom))
+}
+
+fn insert_counter(basic_block_data: &mut BasicBlockData<'_>) {
+    basic_block_data.statements.push(Statement {
+        source_info: basic_block_data.terminator().source_info,
+        kind: StatementKind::ConstEvalCounter,
+    });
+}
index 09546330cec92672a2a5c906ba1d1847c108e7ed..9dbfb089dc665428340c5fc4272e4f494a3def45 100644 (file)
@@ -53,6 +53,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
                 | StatementKind::StorageDead(_)
                 | StatementKind::Coverage(_)
                 | StatementKind::Intrinsic(_)
+                | StatementKind::ConstEvalCounter
                 | StatementKind::Nop => (),
 
                 StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
index 08e296a837127b72911b152275b7c242ca47d0f9..5c5baa68e5889362e359aacc23ca9e7706e43666 100644 (file)
@@ -328,7 +328,8 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio
         match &statement.kind {
             StatementKind::Assign(box (dest, rvalue)) => {
                 match rvalue {
-                    Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => {
+                    Rvalue::CopyForDeref(place)
+                    | Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => {
                         // These might've been turned into self-assignments by the replacement
                         // (this includes the original statement we wanted to eliminate).
                         if dest == place {
@@ -577,6 +578,7 @@ fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>, body: &Body<'
                 self.add_place(**place);
             }
             StatementKind::Intrinsic(_)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop
             | StatementKind::Coverage(_)
             | StatementKind::StorageLive(_)
@@ -754,7 +756,7 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> {
     fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
         if let StatementKind::Assign(box (
             lhs,
-            Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
+            Rvalue::CopyForDeref(rhs) | Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
         )) = &statement.kind
         {
             let Some((src, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else {
index b708d780b70050d648557d04f34bf82a1338d60b..aa19b1fdb5efae9dcb89029dba67be035855dc34 100644 (file)
@@ -79,7 +79,7 @@ fn check_bound_args(
         for bound in bounds {
             if let Some(bound_ty) = self.is_pointer_trait(&bound.kind().skip_binder()) {
                 // Get the argument types as they appear in the function signature.
-                let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs();
+                let arg_defs = self.tcx.fn_sig(def_id).subst_identity().skip_binder().inputs();
                 for (arg_num, arg_def) in arg_defs.iter().enumerate() {
                     // For all types reachable from the argument type in the fn sig
                     for generic_inner_ty in arg_def.walk() {
@@ -161,7 +161,8 @@ fn emit_lint(
             .as_ref()
             .assert_crate_local()
             .lint_root;
-        let fn_sig = self.tcx.fn_sig(fn_id);
+        // FIXME: use existing printing routines to print the function signature
+        let fn_sig = self.tcx.fn_sig(fn_id).subst(self.tcx, fn_substs);
         let unsafety = fn_sig.unsafety().prefix_str();
         let abi = match fn_sig.abi() {
             Abi::Rust => String::from(""),
index c097af6161159a7fcec85b6b0bb69a3605fcb8e9..5624e312da1cbe8eeabe9cbc82d219ebea390f86 100644 (file)
@@ -54,7 +54,8 @@
 use crate::simplify;
 use crate::util::expand_aggregate;
 use crate::MirPass;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::pluralize;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::GeneratorKind;
@@ -70,6 +71,9 @@
 };
 use rustc_mir_dataflow::storage::always_storage_live_locals;
 use rustc_mir_dataflow::{self, Analysis};
+use rustc_span::def_id::DefId;
+use rustc_span::symbol::sym;
+use rustc_span::Span;
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::PanicStrategy;
 use std::{iter, ops};
@@ -460,6 +464,104 @@ fn replace_local<'tcx>(
     new_local
 }
 
+/// Transforms the `body` of the generator applying the following transforms:
+///
+/// - Eliminates all the `get_context` calls that async lowering created.
+/// - Replace all `Local` `ResumeTy` types with `&mut Context<'_>` (`context_mut_ref`).
+///
+/// The `Local`s that have their types replaced are:
+/// - The `resume` argument itself.
+/// - The argument to `get_context`.
+/// - The yielded value of a `yield`.
+///
+/// The `ResumeTy` hides a `&mut Context<'_>` behind an unsafe raw pointer, and the
+/// `get_context` function is being used to convert that back to a `&mut Context<'_>`.
+///
+/// Ideally the async lowering would not use the `ResumeTy`/`get_context` indirection,
+/// but rather directly use `&mut Context<'_>`, however that would currently
+/// lead to higher-kinded lifetime errors.
+/// See <https://github.com/rust-lang/rust/issues/105501>.
+///
+/// The async lowering step and the type / lifetime inference / checking are
+/// still using the `ResumeTy` indirection for the time being, and that indirection
+/// is removed here. After this transform, the generator body only knows about `&mut Context<'_>`.
+fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    let context_mut_ref = tcx.mk_task_context();
+
+    // replace the type of the `resume` argument
+    replace_resume_ty_local(tcx, body, Local::new(2), context_mut_ref);
+
+    let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None);
+
+    for bb in BasicBlock::new(0)..body.basic_blocks.next_index() {
+        let bb_data = &body[bb];
+        if bb_data.is_cleanup {
+            continue;
+        }
+
+        match &bb_data.terminator().kind {
+            TerminatorKind::Call { func, .. } => {
+                let func_ty = func.ty(body, tcx);
+                if let ty::FnDef(def_id, _) = *func_ty.kind() {
+                    if def_id == get_context_def_id {
+                        let local = eliminate_get_context_call(&mut body[bb]);
+                        replace_resume_ty_local(tcx, body, local, context_mut_ref);
+                    }
+                } else {
+                    continue;
+                }
+            }
+            TerminatorKind::Yield { resume_arg, .. } => {
+                replace_resume_ty_local(tcx, body, resume_arg.local, context_mut_ref);
+            }
+            _ => {}
+        }
+    }
+}
+
+fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local {
+    let terminator = bb_data.terminator.take().unwrap();
+    if let TerminatorKind::Call { mut args, destination, target, .. } = terminator.kind {
+        let arg = args.pop().unwrap();
+        let local = arg.place().unwrap().local;
+
+        let arg = Rvalue::Use(arg);
+        let assign = Statement {
+            source_info: terminator.source_info,
+            kind: StatementKind::Assign(Box::new((destination, arg))),
+        };
+        bb_data.statements.push(assign);
+        bb_data.terminator = Some(Terminator {
+            source_info: terminator.source_info,
+            kind: TerminatorKind::Goto { target: target.unwrap() },
+        });
+        local
+    } else {
+        bug!();
+    }
+}
+
+#[cfg_attr(not(debug_assertions), allow(unused))]
+fn replace_resume_ty_local<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &mut Body<'tcx>,
+    local: Local,
+    context_mut_ref: Ty<'tcx>,
+) {
+    let local_ty = std::mem::replace(&mut body.local_decls[local].ty, context_mut_ref);
+    // We have to replace the `ResumeTy` that is used for type and borrow checking
+    // with `&mut Context<'_>` in MIR.
+    #[cfg(debug_assertions)]
+    {
+        if let ty::Adt(resume_ty_adt, _) = local_ty.kind() {
+            let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
+            assert_eq!(*resume_ty_adt, expected_adt);
+        } else {
+            panic!("expected `ResumeTy`, found `{:?}`", local_ty);
+        };
+    }
+}
+
 struct LivenessInfo {
     /// Which locals are live across any suspension point.
     saved_locals: GeneratorSavedLocals,
@@ -756,7 +858,7 @@ fn sanitize_witness<'tcx>(
     body: &Body<'tcx>,
     witness: Ty<'tcx>,
     upvars: Vec<Ty<'tcx>>,
-    saved_locals: &GeneratorSavedLocals,
+    layout: &GeneratorLayout<'tcx>,
 ) {
     let did = body.source.def_id();
     let param_env = tcx.param_env(did);
@@ -775,31 +877,36 @@ fn sanitize_witness<'tcx>(
         }
     };
 
-    for (local, decl) in body.local_decls.iter_enumerated() {
-        // Ignore locals which are internal or not saved between yields.
-        if !saved_locals.contains(local) || decl.internal {
+    let mut mismatches = Vec::new();
+    for fty in &layout.field_tys {
+        if fty.ignore_for_traits {
             continue;
         }
-        let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty);
+        let decl_ty = tcx.normalize_erasing_regions(param_env, fty.ty);
 
         // Sanity check that typeck knows about the type of locals which are
         // live across a suspension point
         if !allowed.contains(&decl_ty) && !allowed_upvars.contains(&decl_ty) {
-            span_bug!(
-                body.span,
-                "Broken MIR: generator contains type {} in MIR, \
-                       but typeck only knows about {} and {:?}",
-                decl_ty,
-                allowed,
-                allowed_upvars
-            );
+            mismatches.push(decl_ty);
         }
     }
+
+    if !mismatches.is_empty() {
+        span_bug!(
+            body.span,
+            "Broken MIR: generator contains type {:?} in MIR, \
+                       but typeck only knows about {} and {:?}",
+            mismatches,
+            allowed,
+            allowed_upvars
+        );
+    }
 }
 
 fn compute_layout<'tcx>(
+    tcx: TyCtxt<'tcx>,
     liveness: LivenessInfo,
-    body: &mut Body<'tcx>,
+    body: &Body<'tcx>,
 ) -> (
     FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>,
     GeneratorLayout<'tcx>,
@@ -817,9 +924,33 @@ fn compute_layout<'tcx>(
     let mut locals = IndexVec::<GeneratorSavedLocal, _>::new();
     let mut tys = IndexVec::<GeneratorSavedLocal, _>::new();
     for (saved_local, local) in saved_locals.iter_enumerated() {
-        locals.push(local);
-        tys.push(body.local_decls[local].ty);
         debug!("generator saved local {:?} => {:?}", saved_local, local);
+
+        locals.push(local);
+        let decl = &body.local_decls[local];
+        debug!(?decl);
+
+        let ignore_for_traits = if tcx.sess.opts.unstable_opts.drop_tracking_mir {
+            match decl.local_info {
+                // Do not include raw pointers created from accessing `static` items, as those could
+                // well be re-created by another access to the same static.
+                Some(box LocalInfo::StaticRef { is_thread_local, .. }) => !is_thread_local,
+                // Fake borrows are only read by fake reads, so do not have any reality in
+                // post-analysis MIR.
+                Some(box LocalInfo::FakeBorrow) => true,
+                _ => false,
+            }
+        } else {
+            // FIXME(#105084) HIR-based drop tracking does not account for all the temporaries that
+            // MIR building may introduce. This leads to wrongly ignored types, but this is
+            // necessary for internal consistency and to avoid ICEs.
+            decl.internal
+        };
+        let decl =
+            GeneratorSavedTy { ty: decl.ty, source_info: decl.source_info, ignore_for_traits };
+        debug!(?decl);
+
+        tys.push(decl);
     }
 
     // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states.
@@ -849,7 +980,7 @@ fn compute_layout<'tcx>(
             // just use the first one here. That's fine; fields do not move
             // around inside generators, so it doesn't matter which variant
             // index we access them by.
-            remap.entry(locals[saved_local]).or_insert((tys[saved_local], variant_index, idx));
+            remap.entry(locals[saved_local]).or_insert((tys[saved_local].ty, variant_index, idx));
         }
         variant_fields.push(fields);
         variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]);
@@ -859,6 +990,7 @@ fn compute_layout<'tcx>(
 
     let layout =
         GeneratorLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts };
+    debug!(?layout);
 
     (remap, layout, storage_liveness)
 }
@@ -1253,6 +1385,42 @@ fn create_cases<'tcx>(
         .collect()
 }
 
+#[instrument(level = "debug", skip(tcx), ret)]
+pub(crate) fn mir_generator_witnesses<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+) -> GeneratorLayout<'tcx> {
+    assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir);
+    let def_id = def_id.expect_local();
+
+    let (body, _) = tcx.mir_promoted(ty::WithOptConstParam::unknown(def_id));
+    let body = body.borrow();
+    let body = &*body;
+
+    // The first argument is the generator type passed by value
+    let gen_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
+
+    // Get the interior types and substs which typeck computed
+    let movable = match *gen_ty.kind() {
+        ty::Generator(_, _, movability) => movability == hir::Movability::Movable,
+        _ => span_bug!(body.span, "unexpected generator type {}", gen_ty),
+    };
+
+    // When first entering the generator, move the resume argument into its new local.
+    let always_live_locals = always_storage_live_locals(&body);
+
+    let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
+
+    // Extract locals which are live across suspension point into `layout`
+    // `remap` gives a mapping from local indices onto generator struct indices
+    // `storage_liveness` tells us which locals have live storage at suspension points
+    let (_, generator_layout, _) = compute_layout(tcx, liveness_info, body);
+
+    check_suspend_tys(tcx, &generator_layout, &body);
+
+    generator_layout
+}
+
 impl<'tcx> MirPass<'tcx> for StateTransform {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let Some(yield_ty) = body.yield_ty() else {
@@ -1265,14 +1433,14 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // The first argument is the generator type passed by value
         let gen_ty = body.local_decls.raw[1].ty;
 
-        // Get the interior types and substs which typeck computed
-        let (upvars, interior, discr_ty, movable) = match *gen_ty.kind() {
+        // Get the discriminant type and substs which typeck computed
+        let (discr_ty, upvars, interior, movable) = match *gen_ty.kind() {
             ty::Generator(_, substs, movability) => {
                 let substs = substs.as_generator();
                 (
-                    substs.upvar_tys().collect(),
-                    substs.witness(),
                     substs.discr_ty(tcx),
+                    substs.upvar_tys().collect::<Vec<_>>(),
+                    substs.witness(),
                     movability == hir::Movability::Movable,
                 )
             }
@@ -1283,13 +1451,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             }
         };
 
-        let is_async_kind = body.generator_kind().unwrap() != GeneratorKind::Gen;
+        let is_async_kind = matches!(body.generator_kind(), Some(GeneratorKind::Async(_)));
         let (state_adt_ref, state_substs) = if is_async_kind {
             // Compute Poll<return_ty>
-            let state_did = tcx.require_lang_item(LangItem::Poll, None);
-            let state_adt_ref = tcx.adt_def(state_did);
-            let state_substs = tcx.intern_substs(&[body.return_ty().into()]);
-            (state_adt_ref, state_substs)
+            let poll_did = tcx.require_lang_item(LangItem::Poll, None);
+            let poll_adt_ref = tcx.adt_def(poll_did);
+            let poll_substs = tcx.intern_substs(&[body.return_ty().into()]);
+            (poll_adt_ref, poll_substs)
         } else {
             // Compute GeneratorState<yield_ty, return_ty>
             let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
@@ -1303,13 +1471,19 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // RETURN_PLACE then is a fresh unused local with type ret_ty.
         let new_ret_local = replace_local(RETURN_PLACE, ret_ty, body, tcx);
 
+        // Replace all occurrences of `ResumeTy` with `&mut Context<'_>` within async bodies.
+        if is_async_kind {
+            transform_async_context(tcx, body);
+        }
+
         // We also replace the resume argument and insert an `Assign`.
         // This is needed because the resume argument `_2` might be live across a `yield`, in which
         // case there is no `Assign` to it that the transform can turn into a store to the generator
         // state. After the yield the slot in the generator state would then be uninitialized.
         let resume_local = Local::new(2);
-        let new_resume_local =
-            replace_local(resume_local, body.local_decls[resume_local].ty, body, tcx);
+        let resume_ty =
+            if is_async_kind { tcx.mk_task_context() } else { body.local_decls[resume_local].ty };
+        let new_resume_local = replace_local(resume_local, resume_ty, body, tcx);
 
         // When first entering the generator, move the resume argument into its new local.
         let source_info = SourceInfo::outermost(body.span);
@@ -1330,8 +1504,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let liveness_info =
             locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
 
-        sanitize_witness(tcx, body, interior, upvars, &liveness_info.saved_locals);
-
         if tcx.sess.opts.unstable_opts.validate_mir {
             let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias {
                 assigned_local: None,
@@ -1345,7 +1517,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // Extract locals which are live across suspension point into `layout`
         // `remap` gives a mapping from local indices onto generator struct indices
         // `storage_liveness` tells us which locals have live storage at suspension points
-        let (remap, layout, storage_liveness) = compute_layout(liveness_info, body);
+        let (remap, layout, storage_liveness) = compute_layout(tcx, liveness_info, body);
+
+        if tcx.sess.opts.unstable_opts.validate_mir
+            && !tcx.sess.opts.unstable_opts.drop_tracking_mir
+        {
+            sanitize_witness(tcx, body, interior, upvars, &layout);
+        }
 
         let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id()));
 
@@ -1479,6 +1657,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
         }
     }
@@ -1527,3 +1706,212 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
         }
     }
 }
+
+fn check_suspend_tys<'tcx>(tcx: TyCtxt<'tcx>, layout: &GeneratorLayout<'tcx>, body: &Body<'tcx>) {
+    let mut linted_tys = FxHashSet::default();
+
+    // We want a user-facing param-env.
+    let param_env = tcx.param_env(body.source.def_id());
+
+    for (variant, yield_source_info) in
+        layout.variant_fields.iter().zip(&layout.variant_source_info)
+    {
+        debug!(?variant);
+        for &local in variant {
+            let decl = &layout.field_tys[local];
+            debug!(?decl);
+
+            if !decl.ignore_for_traits && linted_tys.insert(decl.ty) {
+                let Some(hir_id) = decl.source_info.scope.lint_root(&body.source_scopes) else { continue };
+
+                check_must_not_suspend_ty(
+                    tcx,
+                    decl.ty,
+                    hir_id,
+                    param_env,
+                    SuspendCheckData {
+                        source_span: decl.source_info.span,
+                        yield_span: yield_source_info.span,
+                        plural_len: 1,
+                        ..Default::default()
+                    },
+                );
+            }
+        }
+    }
+}
+
+#[derive(Default)]
+struct SuspendCheckData<'a> {
+    source_span: Span,
+    yield_span: Span,
+    descr_pre: &'a str,
+    descr_post: &'a str,
+    plural_len: usize,
+}
+
+// Returns whether it emitted a diagnostic or not
+// Note that this fn and the proceeding one are based on the code
+// for creating must_use diagnostics
+//
+// Note that this technique was chosen over things like a `Suspend` marker trait
+// as it is simpler and has precedent in the compiler
+fn check_must_not_suspend_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+    hir_id: hir::HirId,
+    param_env: ty::ParamEnv<'tcx>,
+    data: SuspendCheckData<'_>,
+) -> bool {
+    if ty.is_unit() {
+        return false;
+    }
+
+    let plural_suffix = pluralize!(data.plural_len);
+
+    debug!("Checking must_not_suspend for {}", ty);
+
+    match *ty.kind() {
+        ty::Adt(..) if ty.is_box() => {
+            let boxed_ty = ty.boxed_ty();
+            let descr_pre = &format!("{}boxed ", data.descr_pre);
+            check_must_not_suspend_ty(
+                tcx,
+                boxed_ty,
+                hir_id,
+                param_env,
+                SuspendCheckData { descr_pre, ..data },
+            )
+        }
+        ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data),
+        // FIXME: support adding the attribute to TAITs
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
+            let mut has_emitted = false;
+            for &(predicate, _) in tcx.explicit_item_bounds(def) {
+                // We only look at the `DefId`, so it is safe to skip the binder here.
+                if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) =
+                    predicate.kind().skip_binder()
+                {
+                    let def_id = poly_trait_predicate.trait_ref.def_id;
+                    let descr_pre = &format!("{}implementer{} of ", data.descr_pre, plural_suffix);
+                    if check_must_not_suspend_def(
+                        tcx,
+                        def_id,
+                        hir_id,
+                        SuspendCheckData { descr_pre, ..data },
+                    ) {
+                        has_emitted = true;
+                        break;
+                    }
+                }
+            }
+            has_emitted
+        }
+        ty::Dynamic(binder, _, _) => {
+            let mut has_emitted = false;
+            for predicate in binder.iter() {
+                if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
+                    let def_id = trait_ref.def_id;
+                    let descr_post = &format!(" trait object{}{}", plural_suffix, data.descr_post);
+                    if check_must_not_suspend_def(
+                        tcx,
+                        def_id,
+                        hir_id,
+                        SuspendCheckData { descr_post, ..data },
+                    ) {
+                        has_emitted = true;
+                        break;
+                    }
+                }
+            }
+            has_emitted
+        }
+        ty::Tuple(fields) => {
+            let mut has_emitted = false;
+            for (i, ty) in fields.iter().enumerate() {
+                let descr_post = &format!(" in tuple element {i}");
+                if check_must_not_suspend_ty(
+                    tcx,
+                    ty,
+                    hir_id,
+                    param_env,
+                    SuspendCheckData { descr_post, ..data },
+                ) {
+                    has_emitted = true;
+                }
+            }
+            has_emitted
+        }
+        ty::Array(ty, len) => {
+            let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix);
+            check_must_not_suspend_ty(
+                tcx,
+                ty,
+                hir_id,
+                param_env,
+                SuspendCheckData {
+                    descr_pre,
+                    plural_len: len.try_eval_usize(tcx, param_env).unwrap_or(0) as usize + 1,
+                    ..data
+                },
+            )
+        }
+        // If drop tracking is enabled, we want to look through references, since the referrent
+        // may not be considered live across the await point.
+        ty::Ref(_region, ty, _mutability) => {
+            let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix);
+            check_must_not_suspend_ty(
+                tcx,
+                ty,
+                hir_id,
+                param_env,
+                SuspendCheckData { descr_pre, ..data },
+            )
+        }
+        _ => false,
+    }
+}
+
+fn check_must_not_suspend_def(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+    hir_id: hir::HirId,
+    data: SuspendCheckData<'_>,
+) -> bool {
+    if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) {
+        let msg = format!(
+            "{}`{}`{} held across a suspend point, but should not be",
+            data.descr_pre,
+            tcx.def_path_str(def_id),
+            data.descr_post,
+        );
+        tcx.struct_span_lint_hir(
+            rustc_session::lint::builtin::MUST_NOT_SUSPEND,
+            hir_id,
+            data.source_span,
+            msg,
+            |lint| {
+                // add span pointing to the offending yield/await
+                lint.span_label(data.yield_span, "the value is held across this suspend point");
+
+                // Add optional reason note
+                if let Some(note) = attr.value_str() {
+                    // FIXME(guswynn): consider formatting this better
+                    lint.span_note(data.source_span, note.as_str());
+                }
+
+                // Add some quick suggestions on what to do
+                // FIXME: can `drop` work as a suggestion here as well?
+                lint.span_help(
+                    data.source_span,
+                    "consider using a block (`{ ... }`) \
+                    to shrink the value's scope, ending before the suspend point",
+                )
+            },
+        );
+
+        true
+    } else {
+        false
+    }
+}
index 4219e6280ebbca481424a6b7ee3bbef6ed25d41c..84640b703c8021659b3cd61df5253896ce69086f 100644 (file)
@@ -331,7 +331,7 @@ fn resolve_callsite(
                     return None;
                 }
 
-                let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
+                let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs);
                 let source_info = SourceInfo { span: fn_span, ..terminator.source_info };
 
                 return Some(CallSite { callee, fn_sig, block: bb, target, source_info });
@@ -542,6 +542,21 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
                     destination
                 };
 
+                // Always create a local to hold the destination, as `RETURN_PLACE` may appear
+                // where a full `Place` is not allowed.
+                let (remap_destination, destination_local) = if let Some(d) = dest.as_local() {
+                    (false, d)
+                } else {
+                    (
+                        true,
+                        self.new_call_temp(
+                            caller_body,
+                            &callsite,
+                            destination.ty(caller_body, self.tcx).ty,
+                        ),
+                    )
+                };
+
                 // Copy the arguments if needed.
                 let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body);
 
@@ -560,7 +575,7 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
                     new_locals: Local::new(caller_body.local_decls.len())..,
                     new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
                     new_blocks: BasicBlock::new(caller_body.basic_blocks.len())..,
-                    destination: dest,
+                    destination: destination_local,
                     callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
                     callsite,
                     cleanup_block: cleanup,
@@ -591,6 +606,16 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
                     // To avoid repeated O(n) insert, push any new statements to the end and rotate
                     // the slice once.
                     let mut n = 0;
+                    if remap_destination {
+                        caller_body[block].statements.push(Statement {
+                            source_info: callsite.source_info,
+                            kind: StatementKind::Assign(Box::new((
+                                dest,
+                                Rvalue::Use(Operand::Move(destination_local.into())),
+                            ))),
+                        });
+                        n += 1;
+                    }
                     for local in callee_body.vars_and_temps_iter().rev() {
                         if !callee_body.local_decls[local].internal
                             && integrator.always_live_locals.contains(local)
@@ -922,12 +947,12 @@ fn visit_projection_elem(
                             return;
                         };
 
-                        let Some(&f_ty) = layout.field_tys.get(local) else {
+                        let Some(f_ty) = layout.field_tys.get(local) else {
                             self.validation = Err("malformed MIR");
                             return;
                         };
 
-                        f_ty
+                        f_ty.ty
                     } else {
                         let Some(f_ty) = substs.as_generator().prefix_tys().nth(f.index()) else {
                             self.validation = Err("malformed MIR");
@@ -959,7 +984,7 @@ struct Integrator<'a, 'tcx> {
     new_locals: RangeFrom<Local>,
     new_scopes: RangeFrom<SourceScope>,
     new_blocks: RangeFrom<BasicBlock>,
-    destination: Place<'tcx>,
+    destination: Local,
     callsite_scope: SourceScopeData<'tcx>,
     callsite: &'a CallSite<'tcx>,
     cleanup_block: Option<BasicBlock>,
@@ -972,7 +997,7 @@ struct Integrator<'a, 'tcx> {
 impl Integrator<'_, '_> {
     fn map_local(&self, local: Local) -> Local {
         let new = if local == RETURN_PLACE {
-            self.destination.local
+            self.destination
         } else {
             let idx = local.index() - 1;
             if idx < self.args.len() {
@@ -1053,27 +1078,6 @@ fn visit_span(&mut self, span: &mut Span) {
         *span = span.fresh_expansion(self.expn_data);
     }
 
-    fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        for elem in place.projection {
-            // FIXME: Make sure that return place is not used in an indexing projection, since it
-            // won't be rebased as it is supposed to be.
-            assert_ne!(ProjectionElem::Index(RETURN_PLACE), elem);
-        }
-
-        // If this is the `RETURN_PLACE`, we need to rebase any projections onto it.
-        let dest_proj_len = self.destination.projection.len();
-        if place.local == RETURN_PLACE && dest_proj_len > 0 {
-            let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len());
-            projs.extend(self.destination.projection);
-            projs.extend(place.projection);
-
-            place.projection = self.tcx.intern_place_elems(&*projs);
-        }
-        // Handles integrating any locals that occur in the base
-        // or projections
-        self.super_place(place, context, location)
-    }
-
     fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
         self.in_cleanup_block = data.is_cleanup;
         self.super_basic_block_data(block, data);
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 16b8a901f36512140a87c147910aeabcec5eadfe..abf89e550b14922973d1afeb584eb79ebd97bc97 100644 (file)
@@ -54,7 +54,9 @@
 mod const_goto;
 mod const_prop;
 mod const_prop_lint;
+mod copy_prop;
 mod coverage;
+mod ctfe_limit;
 mod dataflow_const_prop;
 mod dead_store_elimination;
 mod deaggregator;
 mod reveal_all;
 mod separate_const_switch;
 mod shim;
+mod ssa;
 // This pass is public to allow external drivers to perform MIR cleanup
 pub mod simplify;
 mod simplify_branches;
 mod simplify_comparison_integral;
-mod simplify_try;
 mod sroa;
 mod uninhabited_enum_branching;
 mod unreachable_prop;
@@ -124,6 +126,7 @@ pub fn provide(providers: &mut Providers) {
         mir_drops_elaborated_and_const_checked,
         mir_for_ctfe,
         mir_for_ctfe_of_const_arg,
+        mir_generator_witnesses: generator::mir_generator_witnesses,
         optimized_mir,
         is_mir_available,
         is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did),
@@ -410,6 +413,8 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
         }
     }
 
+    pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None);
+
     debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE");
 
     body
@@ -426,6 +431,9 @@ fn mir_drops_elaborated_and_const_checked(
         return tcx.mir_drops_elaborated_and_const_checked(def);
     }
 
+    if tcx.generator_kind(def.did).is_some() && tcx.sess.opts.unstable_opts.drop_tracking_mir {
+        tcx.ensure().mir_generator_witnesses(def.did);
+    }
     let mir_borrowck = tcx.mir_borrowck_opt_const_arg(def);
 
     let is_fn_like = tcx.def_kind(def.did).is_fn_like();
@@ -487,7 +495,6 @@ fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>
 fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let passes: &[&dyn MirPass<'tcx>] = &[
         &cleanup_post_borrowck::CleanupPostBorrowck,
-        &simplify_branches::SimplifyConstCondition::new("initial"),
         &remove_noop_landing_pads::RemoveNoopLandingPads,
         &simplify::SimplifyCfg::new("early-opt"),
         &deref_separator::Derefer,
@@ -558,6 +565,7 @@ fn o1<T>(x: T) -> WithMinOptLevel<T> {
             &instcombine::InstCombine,
             &separate_const_switch::SeparateConstSwitch,
             &simplify::SimplifyLocals::new("before-const-prop"),
+            &copy_prop::CopyProp,
             //
             // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
             &const_prop::ConstProp,
@@ -568,8 +576,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")),
index f1bbf2ea7e8ea3aaf7b40307ba110dcd7346b4a3..e3a03aa08af4bdf87db93f780da21ff176657674 100644 (file)
@@ -35,6 +35,7 @@ fn is_nop_landing_pad(
                 | StatementKind::StorageDead(_)
                 | StatementKind::AscribeUserType(..)
                 | StatementKind::Coverage(..)
+                | StatementKind::ConstEvalCounter
                 | StatementKind::Nop => {
                     // These are all noops in a landing pad
                 }
index 2f116aaa95849bd075b94179109e2bc1a210d1d9..a24d2d34d791b96e53a654610d52ef95f5ce035e 100644 (file)
@@ -250,6 +250,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
             | StatementKind::Coverage(_)
             | StatementKind::StorageDead(_)
             | StatementKind::Intrinsic(_)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
         }
     }
@@ -318,6 +319,7 @@ fn find_determining_place<'tcx>(
             | StatementKind::AscribeUserType(_, _)
             | StatementKind::Coverage(_)
             | StatementKind::Intrinsic(_)
+            | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
 
             // If the discriminant is set, it is always set
index dace540fa29d2596739379f140d446909c08cc5f..8d4fe74e7d3925f7e624623a25a01b112b994b53 100644 (file)
@@ -152,7 +152,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
     } else {
         InternalSubsts::identity_for_item(tcx, def_id)
     };
-    let sig = tcx.bound_fn_sig(def_id).subst(tcx, substs);
+    let sig = tcx.fn_sig(def_id).subst(tcx, substs);
     let sig = tcx.erase_late_bound_regions(sig);
     let span = tcx.def_span(def_id);
 
@@ -363,7 +363,7 @@ fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self {
         // we must subst the self_ty because it's
         // otherwise going to be TySelf and we can't index
         // or access fields of a Place of type TySelf.
-        let sig = tcx.bound_fn_sig(def_id).subst(tcx, &[self_ty.into()]);
+        let sig = tcx.fn_sig(def_id).subst(tcx, &[self_ty.into()]);
         let sig = tcx.erase_late_bound_regions(sig);
         let span = tcx.def_span(def_id);
 
@@ -606,7 +606,7 @@ fn build_call_shim<'tcx>(
     };
 
     let def_id = instance.def_id();
-    let sig = tcx.bound_fn_sig(def_id);
+    let sig = tcx.fn_sig(def_id);
     let sig = sig.map_bound(|sig| tcx.erase_late_bound_regions(sig));
 
     assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body());
@@ -798,7 +798,11 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
     let param_env = tcx.param_env(ctor_id);
 
     // Normalize the sig.
-    let sig = tcx.fn_sig(ctor_id).no_bound_vars().expect("LBR in ADT constructor signature");
+    let sig = tcx
+        .fn_sig(ctor_id)
+        .subst_identity()
+        .no_bound_vars()
+        .expect("LBR in ADT constructor signature");
     let sig = tcx.normalize_erasing_regions(param_env, sig);
 
     let ty::Adt(adt_def, substs) = sig.output().kind() else {
index 8f6abe7a912feefefadb5ac24abbc8dbe97c3af9..ced97b2c788426f607bb59602b7d83adb43bd113 100644 (file)
@@ -404,6 +404,18 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     }
 }
 
+pub fn remove_unused_definitions<'tcx>(body: &mut Body<'tcx>) {
+    // First, we're going to get a count of *actual* uses for every `Local`.
+    let mut used_locals = UsedLocals::new(body);
+
+    // Next, we're going to remove any `Local` with zero actual uses. When we remove those
+    // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals`
+    // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from
+    // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a
+    // fixedpoint where there are no more unused locals.
+    remove_unused_definitions_helper(&mut used_locals, body);
+}
+
 pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
     // First, we're going to get a count of *actual* uses for every `Local`.
     let mut used_locals = UsedLocals::new(body);
@@ -413,7 +425,7 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
     // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from
     // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a
     // fixedpoint where there are no more unused locals.
-    remove_unused_definitions(&mut used_locals, body);
+    remove_unused_definitions_helper(&mut used_locals, body);
 
     // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s.
     let map = make_local_map(&mut body.local_decls, &used_locals);
@@ -517,7 +529,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                 self.super_statement(statement, location);
             }
 
-            StatementKind::Nop => {}
+            StatementKind::ConstEvalCounter | StatementKind::Nop => {}
 
             StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {}
 
@@ -548,7 +560,7 @@ fn visit_local(&mut self, local: Local, _ctx: PlaceContext, _location: Location)
 }
 
 /// Removes unused definitions. Updates the used locals to reflect the changes made.
-fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>) {
+fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Body<'_>) {
     // The use counts are updated as we remove the statements. A local might become unused
     // during the retain operation, leading to a temporary inconsistency (storage statements or
     // definitions referencing the local might remain). For correctness it is crucial that this
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 3a2bf051516554bc6f6acdf220f42a604a5de656..42124f5a4808d0a3ff074da042b6db40791be5e1 100644 (file)
@@ -215,7 +215,7 @@ struct ReplacementVisitor<'tcx, 'll> {
     replacements: ReplacementMap<'tcx>,
     /// This is used to check that we are not leaving references to replaced locals behind.
     all_dead_locals: BitSet<Local>,
-    /// Pre-computed list of all "new" locals for each "old" local.  This is used to expand storage
+    /// Pre-computed list of all "new" locals for each "old" local. This is used to expand storage
     /// and deinit statement and debuginfo.
     fragments: IndexVec<Local, Vec<(&'tcx [PlaceElem<'tcx>], Local)>>,
 }
diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs
new file mode 100644 (file)
index 0000000..bc3fe65
--- /dev/null
@@ -0,0 +1,222 @@
+use either::Either;
+use rustc_data_structures::graph::dominators::Dominators;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
+use rustc_middle::middle::resolve_lifetime::Set1;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
+use rustc_middle::ty::{ParamEnv, TyCtxt};
+
+#[derive(Debug)]
+pub struct SsaLocals {
+    /// Assignments to each local. This defines whether the local is SSA.
+    assignments: IndexVec<Local, Set1<LocationExtended>>,
+    /// We visit the body in reverse postorder, to ensure each local is assigned before it is used.
+    /// We remember the order in which we saw the assignments to compute the SSA values in a single
+    /// pass.
+    assignment_order: Vec<Local>,
+    /// Copy equivalence classes between locals. See `copy_classes` for documentation.
+    copy_classes: IndexVec<Local, Local>,
+}
+
+impl SsaLocals {
+    pub fn new<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+        body: &Body<'tcx>,
+        borrowed_locals: &BitSet<Local>,
+    ) -> SsaLocals {
+        let assignment_order = Vec::new();
+
+        let assignments = IndexVec::from_elem(Set1::Empty, &body.local_decls);
+        let dominators = body.basic_blocks.dominators();
+        let mut visitor = SsaVisitor { assignments, assignment_order, dominators };
+
+        for (local, decl) in body.local_decls.iter_enumerated() {
+            if matches!(body.local_kind(local), LocalKind::Arg) {
+                visitor.assignments[local] = Set1::One(LocationExtended::Arg);
+            }
+            if borrowed_locals.contains(local) && !decl.ty.is_freeze(tcx, param_env) {
+                visitor.assignments[local] = Set1::Many;
+            }
+        }
+
+        for (bb, data) in traversal::reverse_postorder(body) {
+            visitor.visit_basic_block_data(bb, data);
+        }
+
+        for var_debug_info in &body.var_debug_info {
+            visitor.visit_var_debug_info(var_debug_info);
+        }
+
+        debug!(?visitor.assignments);
+
+        visitor
+            .assignment_order
+            .retain(|&local| matches!(visitor.assignments[local], Set1::One(_)));
+        debug!(?visitor.assignment_order);
+
+        let copy_classes = compute_copy_classes(&visitor, body);
+
+        SsaLocals {
+            assignments: visitor.assignments,
+            assignment_order: visitor.assignment_order,
+            copy_classes,
+        }
+    }
+
+    pub fn is_ssa(&self, local: Local) -> bool {
+        matches!(self.assignments[local], Set1::One(_))
+    }
+
+    pub fn assignments<'a, 'tcx>(
+        &'a self,
+        body: &'a Body<'tcx>,
+    ) -> impl Iterator<Item = (Local, &'a Rvalue<'tcx>)> + 'a {
+        self.assignment_order.iter().filter_map(|&local| {
+            if let Set1::One(LocationExtended::Plain(loc)) = self.assignments[local] {
+                // `loc` must point to a direct assignment to `local`.
+                let Either::Left(stmt) = body.stmt_at(loc) else { bug!() };
+                let Some((target, rvalue)) = stmt.kind.as_assign() else { bug!() };
+                assert_eq!(target.as_local(), Some(local));
+                Some((local, rvalue))
+            } else {
+                None
+            }
+        })
+    }
+
+    /// Compute the equivalence classes for locals, based on copy statements.
+    ///
+    /// The returned vector maps each local to the one it copies. In the following case:
+    ///   _a = &mut _0
+    ///   _b = move? _a
+    ///   _c = move? _a
+    ///   _d = move? _c
+    /// We return the mapping
+    ///   _a => _a // not a copy so, represented by itself
+    ///   _b => _a
+    ///   _c => _a
+    ///   _d => _a // transitively through _c
+    ///
+    /// Exception: we do not see through the return place, as it cannot be substituted.
+    pub fn copy_classes(&self) -> &IndexVec<Local, Local> {
+        &self.copy_classes
+    }
+
+    /// Make a property uniform on a copy equivalence class by removing elements.
+    pub fn meet_copy_equivalence(&self, property: &mut BitSet<Local>) {
+        // Consolidate to have a local iff all its copies are.
+        //
+        // `copy_classes` defines equivalence classes between locals. The `local`s that recursively
+        // move/copy the same local all have the same `head`.
+        for (local, &head) in self.copy_classes.iter_enumerated() {
+            // If any copy does not have `property`, then the head is not.
+            if !property.contains(local) {
+                property.remove(head);
+            }
+        }
+        for (local, &head) in self.copy_classes.iter_enumerated() {
+            // If any copy does not have `property`, then the head doesn't either,
+            // then no copy has `property`.
+            if !property.contains(head) {
+                property.remove(local);
+            }
+        }
+
+        // Verify that we correctly computed equivalence classes.
+        #[cfg(debug_assertions)]
+        for (local, &head) in self.copy_classes.iter_enumerated() {
+            assert_eq!(property.contains(local), property.contains(head));
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum LocationExtended {
+    Plain(Location),
+    Arg,
+}
+
+struct SsaVisitor {
+    dominators: Dominators<BasicBlock>,
+    assignments: IndexVec<Local, Set1<LocationExtended>>,
+    assignment_order: Vec<Local>,
+}
+
+impl<'tcx> Visitor<'tcx> for SsaVisitor {
+    fn visit_local(&mut self, local: Local, ctxt: PlaceContext, loc: Location) {
+        match ctxt {
+            PlaceContext::MutatingUse(MutatingUseContext::Store) => {
+                self.assignments[local].insert(LocationExtended::Plain(loc));
+                self.assignment_order.push(local);
+            }
+            // Anything can happen with raw pointers, so remove them.
+            PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
+            | PlaceContext::MutatingUse(_) => self.assignments[local] = Set1::Many,
+            // Immutable borrows are taken into account in `SsaLocals::new` by
+            // removing non-freeze locals.
+            PlaceContext::NonMutatingUse(_) => {
+                let set = &mut self.assignments[local];
+                let assign_dominates = match *set {
+                    Set1::Empty | Set1::Many => false,
+                    Set1::One(LocationExtended::Arg) => true,
+                    Set1::One(LocationExtended::Plain(assign)) => {
+                        assign.successor_within_block().dominates(loc, &self.dominators)
+                    }
+                };
+                // We are visiting a use that is not dominated by an assignment.
+                // Either there is a cycle involved, or we are reading for uninitialized local.
+                // Bail out.
+                if !assign_dominates {
+                    *set = Set1::Many;
+                }
+            }
+            PlaceContext::NonUse(_) => {}
+        }
+    }
+}
+
+#[instrument(level = "trace", skip(ssa, body))]
+fn compute_copy_classes(ssa: &SsaVisitor, body: &Body<'_>) -> IndexVec<Local, Local> {
+    let mut copies = IndexVec::from_fn_n(|l| l, body.local_decls.len());
+
+    for &local in &ssa.assignment_order {
+        debug!(?local);
+
+        if local == RETURN_PLACE {
+            // `_0` is special, we cannot rename it.
+            continue;
+        }
+
+        // This is not SSA: mark that we don't know the value.
+        debug!(assignments = ?ssa.assignments[local]);
+        let Set1::One(LocationExtended::Plain(loc)) = ssa.assignments[local] else { continue };
+
+        // `loc` must point to a direct assignment to `local`.
+        let Either::Left(stmt) = body.stmt_at(loc) else { bug!() };
+        let Some((_target, rvalue)) = stmt.kind.as_assign() else { bug!() };
+        assert_eq!(_target.as_local(), Some(local));
+
+        let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place))
+            = rvalue
+        else { continue };
+
+        let Some(rhs) = place.as_local() else { continue };
+        let Set1::One(_) = ssa.assignments[rhs] else { continue };
+
+        // We visit in `assignment_order`, ie. reverse post-order, so `rhs` has been
+        // visited before `local`, and we just have to copy the representing local.
+        copies[local] = copies[rhs];
+    }
+
+    debug!(?copies);
+
+    // Invariant: `copies` must point to the head of an equivalence class.
+    #[cfg(debug_assertions)]
+    for &head in copies.iter() {
+        assert_eq!(copies[head], head);
+    }
+
+    copies
+}
index b573df4325051306236920cdbdc7f273e3a13395..305f0427e501be6477a03c6adba62c77322ca4e5 100644 (file)
@@ -1296,7 +1296,7 @@ fn push_extra_entry_roots(&mut self) {
         };
 
         let start_def_id = self.tcx.require_lang_item(LangItem::Start, None);
-        let main_ret_ty = self.tcx.fn_sig(main_def_id).output();
+        let main_ret_ty = self.tcx.fn_sig(main_def_id).no_bound_vars().unwrap().output();
 
         // Given that `main()` has no arguments,
         // then its return type cannot have
@@ -1352,6 +1352,8 @@ fn create_mono_items_for_default_impls<'tcx>(
             );
 
             if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
+                let trait_ref = trait_ref.subst_identity();
+
                 let param_env = ty::ParamEnv::reveal_all();
                 let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
                 let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);
index b616ed35d99d7f11c983d0ecebb02f2223e4b08d..f88155e4fc7928a89b6f7cd8faa9d90cf655d391 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(array_windows)]
-#![feature(control_flow_enum)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 #![deny(rustc::untranslatable_diagnostic)]
index c8fc69eb856abdc5b12b202122e5fbde68851f75..cf13d4584a12429d5f05e07bf28119221e8c46b5 100644 (file)
@@ -300,20 +300,20 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
     #[instrument(level = "debug", skip(self))]
     fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !c.has_non_region_param() {
-            return ControlFlow::CONTINUE;
+            return ControlFlow::Continue(());
         }
 
         match c.kind() {
             ty::ConstKind::Param(param) => {
                 debug!(?param);
                 self.unused_parameters.mark_used(param.index);
-                ControlFlow::CONTINUE
+                ControlFlow::Continue(())
             }
             ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs })
                 if matches!(self.tcx.def_kind(def.did), DefKind::AnonConst) =>
             {
                 self.visit_child_body(def.did, substs);
-                ControlFlow::CONTINUE
+                ControlFlow::Continue(())
             }
             _ => c.super_visit_with(self),
         }
@@ -322,7 +322,7 @@ fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
     #[instrument(level = "debug", skip(self))]
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !ty.has_non_region_param() {
-            return ControlFlow::CONTINUE;
+            return ControlFlow::Continue(());
         }
 
         match *ty.kind() {
@@ -330,18 +330,18 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 debug!(?def_id);
                 // Avoid cycle errors with generators.
                 if def_id == self.def_id {
-                    return ControlFlow::CONTINUE;
+                    return ControlFlow::Continue(());
                 }
 
                 // Consider any generic parameters used by any closures/generators as used in the
                 // parent.
                 self.visit_child_body(def_id, substs);
-                ControlFlow::CONTINUE
+                ControlFlow::Continue(())
             }
             ty::Param(param) => {
                 debug!(?param);
                 self.unused_parameters.mark_used(param.index);
-                ControlFlow::CONTINUE
+                ControlFlow::Continue(())
             }
             _ => ty.super_visit_with(self),
         }
index 06b970ad979770b633ed432e5e0e6ed0e6db06ed..054b41b478d60516d53c729faa2f1ecdcd1bb5d9 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 {
@@ -640,6 +649,48 @@ pub(crate) struct MatchArmBodyWithoutBraces {
     pub sub: MatchArmBodyWithoutBracesSugg,
 }
 
+#[derive(Diagnostic)]
+#[diag(parse_inclusive_range_extra_equals)]
+#[note]
+pub(crate) struct InclusiveRangeExtraEquals {
+    #[primary_span]
+    #[suggestion(
+        suggestion_remove_eq,
+        style = "short",
+        code = "..=",
+        applicability = "maybe-incorrect"
+    )]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_inclusive_range_match_arrow)]
+pub(crate) struct InclusiveRangeMatchArrow {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(
+        suggestion_add_space,
+        style = "verbose",
+        code = " ",
+        applicability = "machine-applicable"
+    )]
+    pub after_pat: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_inclusive_range_no_end, code = "E0586")]
+#[note]
+pub(crate) struct InclusiveRangeNoEnd {
+    #[primary_span]
+    #[suggestion(
+        suggestion_open_range,
+        code = "..",
+        applicability = "machine-applicable",
+        style = "short"
+    )]
+    pub span: Span,
+}
+
 #[derive(Subdiagnostic)]
 pub(crate) enum MatchArmBodyWithoutBracesSugg {
     #[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")]
diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs
new file mode 100644 (file)
index 0000000..386bf02
--- /dev/null
@@ -0,0 +1,119 @@
+use super::UnmatchedBrace;
+use rustc_ast::token::Delimiter;
+use rustc_errors::Diagnostic;
+use rustc_span::source_map::SourceMap;
+use rustc_span::Span;
+
+#[derive(Default)]
+pub struct TokenTreeDiagInfo {
+    /// Stack of open delimiters and their spans. Used for error message.
+    pub open_braces: Vec<(Delimiter, Span)>,
+    pub unmatched_braces: Vec<UnmatchedBrace>,
+
+    /// Used only for error recovery when arriving to EOF with mismatched braces.
+    pub last_unclosed_found_span: Option<Span>,
+
+    /// Collect empty block spans that might have been auto-inserted by editors.
+    pub empty_block_spans: Vec<Span>,
+
+    /// Collect the spans of braces (Open, Close). Used only
+    /// for detecting if blocks are empty and only braces.
+    pub matching_block_spans: Vec<(Span, Span)>,
+}
+
+pub fn same_identation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool {
+    match (sm.span_to_margin(open_sp), sm.span_to_margin(close_sp)) {
+        (Some(open_padding), Some(close_padding)) => open_padding == close_padding,
+        _ => false,
+    }
+}
+
+// When we get a `)` or `]` for `{`, we should emit help message here
+// it's more friendly compared to report `unmatched error` in later phase
+pub fn report_missing_open_delim(
+    err: &mut Diagnostic,
+    unmatched_braces: &[UnmatchedBrace],
+) -> bool {
+    let mut reported_missing_open = false;
+    for unmatch_brace in unmatched_braces.iter() {
+        if let Some(delim) = unmatch_brace.found_delim
+            && matches!(delim, Delimiter::Parenthesis | Delimiter::Bracket)
+        {
+            let missed_open = match delim {
+                Delimiter::Parenthesis => "(",
+                Delimiter::Bracket => "[",
+                _ => unreachable!(),
+            };
+            err.span_label(
+                unmatch_brace.found_span.shrink_to_lo(),
+                format!("missing open `{}` for this delimiter", missed_open),
+            );
+            reported_missing_open = true;
+        }
+    }
+    reported_missing_open
+}
+
+pub fn report_suspicious_mismatch_block(
+    err: &mut Diagnostic,
+    diag_info: &TokenTreeDiagInfo,
+    sm: &SourceMap,
+    delim: Delimiter,
+) {
+    if report_missing_open_delim(err, &diag_info.unmatched_braces) {
+        return;
+    }
+
+    let mut matched_spans: Vec<(Span, bool)> = diag_info
+        .matching_block_spans
+        .iter()
+        .map(|&(open, close)| (open.with_hi(close.lo()), same_identation_level(sm, open, close)))
+        .collect();
+
+    // sort by `lo`, so the large block spans in the front
+    matched_spans.sort_by(|a, b| a.0.lo().cmp(&b.0.lo()));
+
+    // We use larger block whose identation is well to cover those inner mismatched blocks
+    // O(N^2) here, but we are on error reporting path, so it is fine
+    for i in 0..matched_spans.len() {
+        let (block_span, same_ident) = matched_spans[i];
+        if same_ident {
+            for j in i + 1..matched_spans.len() {
+                let (inner_block, inner_same_ident) = matched_spans[j];
+                if block_span.contains(inner_block) && !inner_same_ident {
+                    matched_spans[j] = (inner_block, true);
+                }
+            }
+        }
+    }
+
+    // Find the inner-most span candidate for final report
+    let candidate_span =
+        matched_spans.into_iter().rev().find(|&(_, same_ident)| !same_ident).map(|(span, _)| span);
+
+    if let Some(block_span) = candidate_span {
+        err.span_label(block_span.shrink_to_lo(), "this delimiter might not be properly closed...");
+        err.span_label(
+            block_span.shrink_to_hi(),
+            "...as it matches this but it has different indentation",
+        );
+
+        // If there is a empty block in the mismatched span, note it
+        if delim == Delimiter::Brace {
+            for span in diag_info.empty_block_spans.iter() {
+                if block_span.contains(*span) {
+                    err.span_label(*span, "block is empty, you might have not meant to close it");
+                    break;
+                }
+            }
+        }
+    } else {
+        // If there is no suspicious span, give the last properly closed block may help
+        if let Some(parent) = diag_info.matching_block_spans.last()
+            && diag_info.open_braces.last().is_none()
+            && diag_info.empty_block_spans.iter().all(|&sp| sp != parent.0.to(parent.1)) {
+                err.span_label(parent.0, "this opening brace...");
+                err.span_label(parent.1, "...matches this closing brace");
+        }
+    }
+}
index f027843e6b43d469ab5483494543ee9d89b42d98..e957224a03377805bbfb7fa666d60df3c29cb607 100644 (file)
@@ -17,6 +17,7 @@
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{edition::Edition, BytePos, Pos, Span};
 
+mod diagnostics;
 mod tokentrees;
 mod unescape_error_reporting;
 mod unicode_chars;
@@ -52,8 +53,15 @@ pub(crate) fn parse_token_trees<'a>(
     }
 
     let cursor = Cursor::new(src);
-    let string_reader =
-        StringReader { sess, start_pos, pos: start_pos, src, cursor, override_span };
+    let string_reader = StringReader {
+        sess,
+        start_pos,
+        pos: start_pos,
+        src,
+        cursor,
+        override_span,
+        nbsp_is_whitespace: false,
+    };
     tokentrees::TokenTreesReader::parse_all_token_trees(string_reader)
 }
 
@@ -68,6 +76,10 @@ struct StringReader<'a> {
     /// Cursor for getting lexer tokens.
     cursor: Cursor<'a>,
     override_span: Option<Span>,
+    /// When a "unknown start of token: \u{a0}" has already been emitted earlier
+    /// in this file, it's safe to treat further occurrences of the non-breaking
+    /// space character as whitespace.
+    nbsp_is_whitespace: bool,
 }
 
 impl<'a> StringReader<'a> {
@@ -79,7 +91,7 @@ fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span {
     /// preceded by whitespace.
     fn next_token(&mut self) -> (Token, bool) {
         let mut preceded_by_whitespace = false;
-
+        let mut swallow_next_invalid = 0;
         // Skip trivial (whitespace & comments) tokens
         loop {
             let token = self.cursor.advance_token();
@@ -232,19 +244,44 @@ fn next_token(&mut self) -> (Token, bool) {
                 rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
 
                 rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
-                    let c = self.str_from(start).chars().next().unwrap();
+                    // Don't emit diagnostics for sequences of the same invalid token
+                    if swallow_next_invalid > 0 {
+                        swallow_next_invalid -= 1;
+                        continue;
+                    }
+                    let mut it = self.str_from_to_end(start).chars();
+                    let c = it.next().unwrap();
+                    if c == '\u{00a0}' {
+                        // If an error has already been reported on non-breaking
+                        // space characters earlier in the file, treat all
+                        // subsequent occurrences as whitespace.
+                        if self.nbsp_is_whitespace {
+                            preceded_by_whitespace = true;
+                            continue;
+                        }
+                        self.nbsp_is_whitespace = true;
+                    }
+                    let repeats = it.take_while(|c1| *c1 == c).count();
                     let mut err =
-                        self.struct_err_span_char(start, self.pos, "unknown start of token", c);
+                        self.struct_err_span_char(start, self.pos + Pos::from_usize(repeats * c.len_utf8()), "unknown start of token", c);
                     // FIXME: the lexer could be used to turn the ASCII version of unicode
                     // homoglyphs, instead of keeping a table in `check_for_substitution`into the
                     // token. Ideally, this should be inside `rustc_lexer`. However, we should
                     // first remove compound tokens like `<<` from `rustc_lexer`, and then add
                     // fancier error recovery to it, as there will be less overall work to do this
                     // way.
-                    let token = unicode_chars::check_for_substitution(self, start, c, &mut err);
+                    let token = unicode_chars::check_for_substitution(self, start, c, &mut err, repeats+1);
                     if c == '\x00' {
                         err.help("source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used");
                     }
+                    if repeats > 0 {
+                        if repeats == 1 {
+                            err.note(format!("character appears once more"));
+                        } else {
+                            err.note(format!("character appears {repeats} more times"));
+                        }
+                        swallow_next_invalid = repeats;
+                    }
                     err.emit();
                     if let Some(token) = token {
                         token
@@ -471,7 +508,7 @@ fn src_index(&self, pos: BytePos) -> usize {
 
     /// Slice of the source text from `start` up to but excluding `self.pos`,
     /// meaning the slice does not include the character `self.ch`.
-    fn str_from(&self, start: BytePos) -> &str {
+    fn str_from(&self, start: BytePos) -> &'a str {
         self.str_from_to(start, self.pos)
     }
 
@@ -482,10 +519,15 @@ fn symbol_from_to(&self, start: BytePos, end: BytePos) -> Symbol {
     }
 
     /// Slice of the source text spanning from `start` up to but excluding `end`.
-    fn str_from_to(&self, start: BytePos, end: BytePos) -> &str {
+    fn str_from_to(&self, start: BytePos, end: BytePos) -> &'a str {
         &self.src[self.src_index(start)..self.src_index(end)]
     }
 
+    /// Slice of the source text spanning from `start` until the end
+    fn str_from_to_end(&self, start: BytePos) -> &'a str {
+        &self.src[self.src_index(start)..]
+    }
+
     fn report_raw_str_error(&self, start: BytePos, prefix_len: u32) -> ! {
         match rustc_lexer::validate_raw_str(self.str_from(start), prefix_len) {
             Err(RawStrError::InvalidStarter { bad_char }) => {
index b2701817d489ba89c22e8c5692b0e906229bcc36..0de8f79112c654033ef64b8efe0441ff0cb152cf 100644 (file)
@@ -1,29 +1,18 @@
+use super::diagnostics::report_suspicious_mismatch_block;
+use super::diagnostics::same_identation_level;
+use super::diagnostics::TokenTreeDiagInfo;
 use super::{StringReader, UnmatchedBrace};
 use rustc_ast::token::{self, Delimiter, Token};
 use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree};
 use rustc_ast_pretty::pprust::token_to_string;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{PErr, PResult};
-use rustc_span::Span;
 
 pub(super) struct TokenTreesReader<'a> {
     string_reader: StringReader<'a>,
     /// The "next" token, which has been obtained from the `StringReader` but
     /// not yet handled by the `TokenTreesReader`.
     token: Token,
-    /// Stack of open delimiters and their spans. Used for error message.
-    open_braces: Vec<(Delimiter, Span)>,
-    unmatched_braces: Vec<UnmatchedBrace>,
-    /// The type and spans for all braces
-    ///
-    /// Used only for error recovery when arriving to EOF with mismatched braces.
-    matching_delim_spans: Vec<(Delimiter, Span, Span)>,
-    last_unclosed_found_span: Option<Span>,
-    /// Collect empty block spans that might have been auto-inserted by editors.
-    last_delim_empty_block_spans: FxHashMap<Delimiter, Span>,
-    /// Collect the spans of braces (Open, Close). Used only
-    /// for detecting if blocks are empty and only braces.
-    matching_block_spans: Vec<(Span, Span)>,
+    diag_info: TokenTreeDiagInfo,
 }
 
 impl<'a> TokenTreesReader<'a> {
@@ -33,15 +22,10 @@ pub(super) fn parse_all_token_trees(
         let mut tt_reader = TokenTreesReader {
             string_reader,
             token: Token::dummy(),
-            open_braces: Vec::new(),
-            unmatched_braces: Vec::new(),
-            matching_delim_spans: Vec::new(),
-            last_unclosed_found_span: None,
-            last_delim_empty_block_spans: FxHashMap::default(),
-            matching_block_spans: Vec::new(),
+            diag_info: TokenTreeDiagInfo::default(),
         };
         let res = tt_reader.parse_token_trees(/* is_delimited */ false);
-        (res, tt_reader.unmatched_braces)
+        (res, tt_reader.diag_info.unmatched_braces)
     }
 
     // Parse a stream of tokens into a list of `TokenTree`s.
@@ -92,9 +76,9 @@ fn parse_token_trees(&mut self, is_delimited: bool) -> PResult<'a, TokenStream>
     fn eof_err(&mut self) -> PErr<'a> {
         let msg = "this file contains an unclosed delimiter";
         let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
-        for &(_, sp) in &self.open_braces {
+        for &(_, sp) in &self.diag_info.open_braces {
             err.span_label(sp, "unclosed delimiter");
-            self.unmatched_braces.push(UnmatchedBrace {
+            self.diag_info.unmatched_braces.push(UnmatchedBrace {
                 expected_delim: Delimiter::Brace,
                 found_delim: None,
                 found_span: self.token.span,
@@ -103,23 +87,13 @@ fn eof_err(&mut self) -> PErr<'a> {
             });
         }
 
-        if let Some((delim, _)) = self.open_braces.last() {
-            if let Some((_, open_sp, close_sp)) =
-                self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| {
-                    let sm = self.string_reader.sess.source_map();
-                    if let Some(close_padding) = sm.span_to_margin(*close_sp) {
-                        if let Some(open_padding) = sm.span_to_margin(*open_sp) {
-                            return delim == d && close_padding != open_padding;
-                        }
-                    }
-                    false
-                })
-            // these are in reverse order as they get inserted on close, but
-            {
-                // we want the last open/first close
-                err.span_label(*open_sp, "this delimiter might not be properly closed...");
-                err.span_label(*close_sp, "...as it matches this but it has different indentation");
-            }
+        if let Some((delim, _)) = self.diag_info.open_braces.last() {
+            report_suspicious_mismatch_block(
+                &mut err,
+                &self.diag_info,
+                &self.string_reader.sess.source_map(),
+                *delim,
+            )
         }
         err
     }
@@ -128,7 +102,7 @@ fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree {
         // The span for beginning of the delimited section
         let pre_span = self.token.span;
 
-        self.open_braces.push((open_delim, self.token.span));
+        self.diag_info.open_braces.push((open_delim, self.token.span));
 
         // Parse the token trees within the delimiters.
         // We stop at any delimiter so we can try to recover if the user
@@ -137,35 +111,29 @@ fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree {
 
         // Expand to cover the entire delimited token tree
         let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
+        let sm = self.string_reader.sess.source_map();
 
         match self.token.kind {
             // Correct delimiter.
             token::CloseDelim(close_delim) if close_delim == open_delim => {
-                let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
+                let (open_brace, open_brace_span) = self.diag_info.open_braces.pop().unwrap();
                 let close_brace_span = self.token.span;
 
-                if tts.is_empty() {
+                if tts.is_empty() && close_delim == Delimiter::Brace {
                     let empty_block_span = open_brace_span.to(close_brace_span);
-                    let sm = self.string_reader.sess.source_map();
                     if !sm.is_multiline(empty_block_span) {
                         // Only track if the block is in the form of `{}`, otherwise it is
                         // likely that it was written on purpose.
-                        self.last_delim_empty_block_spans.insert(open_delim, empty_block_span);
+                        self.diag_info.empty_block_spans.push(empty_block_span);
                     }
                 }
 
-                //only add braces
+                // only add braces
                 if let (Delimiter::Brace, Delimiter::Brace) = (open_brace, open_delim) {
-                    self.matching_block_spans.push((open_brace_span, close_brace_span));
+                    // Add all the matching spans, we will sort by span later
+                    self.diag_info.matching_block_spans.push((open_brace_span, close_brace_span));
                 }
 
-                if self.open_braces.is_empty() {
-                    // Clear up these spans to avoid suggesting them as we've found
-                    // properly matched delimiters so far for an entire block.
-                    self.matching_delim_spans.clear();
-                } else {
-                    self.matching_delim_spans.push((open_brace, open_brace_span, close_brace_span));
-                }
                 // Move past the closing delimiter.
                 self.token = self.string_reader.next_token().0;
             }
@@ -174,28 +142,25 @@ fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree {
                 let mut unclosed_delimiter = None;
                 let mut candidate = None;
 
-                if self.last_unclosed_found_span != Some(self.token.span) {
+                if self.diag_info.last_unclosed_found_span != Some(self.token.span) {
                     // do not complain about the same unclosed delimiter multiple times
-                    self.last_unclosed_found_span = Some(self.token.span);
+                    self.diag_info.last_unclosed_found_span = Some(self.token.span);
                     // This is a conservative error: only report the last unclosed
                     // delimiter. The previous unclosed delimiters could actually be
                     // closed! The parser just hasn't gotten to them yet.
-                    if let Some(&(_, sp)) = self.open_braces.last() {
+                    if let Some(&(_, sp)) = self.diag_info.open_braces.last() {
                         unclosed_delimiter = Some(sp);
                     };
-                    let sm = self.string_reader.sess.source_map();
-                    if let Some(current_padding) = sm.span_to_margin(self.token.span) {
-                        for (brace, brace_span) in &self.open_braces {
-                            if let Some(padding) = sm.span_to_margin(*brace_span) {
-                                // high likelihood of these two corresponding
-                                if current_padding == padding && brace == &close_delim {
-                                    candidate = Some(*brace_span);
-                                }
-                            }
+                    for (brace, brace_span) in &self.diag_info.open_braces {
+                        if same_identation_level(&sm, self.token.span, *brace_span)
+                            && brace == &close_delim
+                        {
+                            // high likelihood of these two corresponding
+                            candidate = Some(*brace_span);
                         }
                     }
-                    let (tok, _) = self.open_braces.pop().unwrap();
-                    self.unmatched_braces.push(UnmatchedBrace {
+                    let (tok, _) = self.diag_info.open_braces.pop().unwrap();
+                    self.diag_info.unmatched_braces.push(UnmatchedBrace {
                         expected_delim: tok,
                         found_delim: Some(close_delim),
                         found_span: self.token.span,
@@ -203,7 +168,7 @@ fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree {
                         candidate_span: candidate,
                     });
                 } else {
-                    self.open_braces.pop();
+                    self.diag_info.open_braces.pop();
                 }
 
                 // If the incorrect delimiter matches an earlier opening
@@ -213,7 +178,7 @@ fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree {
                 // fn foo() {
                 //     bar(baz(
                 // }  // Incorrect delimiter but matches the earlier `{`
-                if !self.open_braces.iter().any(|&(b, _)| b == close_delim) {
+                if !self.diag_info.open_braces.iter().any(|&(b, _)| b == close_delim) {
                     self.token = self.string_reader.next_token().0;
                 }
             }
@@ -236,22 +201,12 @@ fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'a> {
         let mut err =
             self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg);
 
-        // Braces are added at the end, so the last element is the biggest block
-        if let Some(parent) = self.matching_block_spans.last() {
-            if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) {
-                // Check if the (empty block) is in the last properly closed block
-                if (parent.0.to(parent.1)).contains(span) {
-                    err.span_label(span, "block is empty, you might have not meant to close it");
-                } else {
-                    err.span_label(parent.0, "this opening brace...");
-                    err.span_label(parent.1, "...matches this closing brace");
-                }
-            } else {
-                err.span_label(parent.0, "this opening brace...");
-                err.span_label(parent.1, "...matches this closing brace");
-            }
-        }
-
+        report_suspicious_mismatch_block(
+            &mut err,
+            &self.diag_info,
+            &self.string_reader.sess.source_map(),
+            delim,
+        );
         err.span_label(self.token.span, "unexpected closing delimiter");
         err
     }
index f1b50296e2565a858e0442b88e192e1fdf12e7e2..34d003ccfa7b4fbde64ca4b7cf6ba25f0341cc30 100644 (file)
 use rustc_span::{symbol::kw, BytePos, Pos, Span};
 
 #[rustfmt::skip] // for line breaks
-pub(crate) const UNICODE_ARRAY: &[(char, &str, char)] = &[
-    ('
', "Line Separator", ' '),
-    ('
', "Paragraph Separator", ' '),
-    (' ', "Ogham Space mark", ' '),
-    (' ', "En Quad", ' '),
-    (' ', "Em Quad", ' '),
-    (' ', "En Space", ' '),
-    (' ', "Em Space", ' '),
-    (' ', "Three-Per-Em Space", ' '),
-    (' ', "Four-Per-Em Space", ' '),
-    (' ', "Six-Per-Em Space", ' '),
-    (' ', "Punctuation Space", ' '),
-    (' ', "Thin Space", ' '),
-    (' ', "Hair Space", ' '),
-    (' ', "Medium Mathematical Space", ' '),
-    (' ', "No-Break Space", ' '),
-    (' ', "Figure Space", ' '),
-    (' ', "Narrow No-Break Space", ' '),
-    (' ', "Ideographic Space", ' '),
-
-    ('ߺ', "Nko Lajanyalan", '_'),
-    ('﹍', "Dashed Low Line", '_'),
-    ('﹎', "Centreline Low Line", '_'),
-    ('﹏', "Wavy Low Line", '_'),
-    ('_', "Fullwidth Low Line", '_'),
-
-    ('‐', "Hyphen", '-'),
-    ('‑', "Non-Breaking Hyphen", '-'),
-    ('‒', "Figure Dash", '-'),
-    ('–', "En Dash", '-'),
-    ('—', "Em Dash", '-'),
-    ('﹘', "Small Em Dash", '-'),
-    ('۔', "Arabic Full Stop", '-'),
-    ('⁃', "Hyphen Bullet", '-'),
-    ('˗', "Modifier Letter Minus Sign", '-'),
-    ('−', "Minus Sign", '-'),
-    ('➖', "Heavy Minus Sign", '-'),
-    ('Ⲻ', "Coptic Letter Dialect-P Ni", '-'),
-    ('ー', "Katakana-Hiragana Prolonged Sound Mark", '-'),
-    ('-', "Fullwidth Hyphen-Minus", '-'),
-    ('―', "Horizontal Bar", '-'),
-    ('─', "Box Drawings Light Horizontal", '-'),
-    ('━', "Box Drawings Heavy Horizontal", '-'),
-    ('㇐', "CJK Stroke H", '-'),
-    ('ꟷ', "Latin Epigraphic Letter Sideways I", '-'),
-    ('ᅳ', "Hangul Jungseong Eu", '-'),
-    ('ㅡ', "Hangul Letter Eu", '-'),
-    ('一', "CJK Unified Ideograph-4E00", '-'),
-    ('⼀', "Kangxi Radical One", '-'),
-
-    ('؍', "Arabic Date Separator", ','),
-    ('٫', "Arabic Decimal Separator", ','),
-    ('‚', "Single Low-9 Quotation Mark", ','),
-    ('¸', "Cedilla", ','),
-    ('ꓹ', "Lisu Letter Tone Na Po", ','),
-    (',', "Fullwidth Comma", ','),
-
-    (';', "Greek Question Mark", ';'),
-    (';', "Fullwidth Semicolon", ';'),
-    ('︔', "Presentation Form For Vertical Semicolon", ';'),
-
-    ('ः', "Devanagari Sign Visarga", ':'),
-    ('ઃ', "Gujarati Sign Visarga", ':'),
-    (':', "Fullwidth Colon", ':'),
-    ('։', "Armenian Full Stop", ':'),
-    ('܃', "Syriac Supralinear Colon", ':'),
-    ('܄', "Syriac Sublinear Colon", ':'),
-    ('᛬', "Runic Multiple Punctuation", ':'),
-    ('︰', "Presentation Form For Vertical Two Dot Leader", ':'),
-    ('᠃', "Mongolian Full Stop", ':'),
-    ('᠉', "Mongolian Manchu Full Stop", ':'),
-    ('⁚', "Two Dot Punctuation", ':'),
-    ('׃', "Hebrew Punctuation Sof Pasuq", ':'),
-    ('˸', "Modifier Letter Raised Colon", ':'),
-    ('꞉', "Modifier Letter Colon", ':'),
-    ('∶', "Ratio", ':'),
-    ('ː', "Modifier Letter Triangular Colon", ':'),
-    ('ꓽ', "Lisu Letter Tone Mya Jeu", ':'),
-    ('︓', "Presentation Form For Vertical Colon", ':'),
-
-    ('!', "Fullwidth Exclamation Mark", '!'),
-    ('ǃ', "Latin Letter Retroflex Click", '!'),
-    ('ⵑ', "Tifinagh Letter Tuareg Yang", '!'),
-    ('︕', "Presentation Form For Vertical Exclamation Mark", '!'),
-
-    ('ʔ', "Latin Letter Glottal Stop", '?'),
-    ('Ɂ', "Latin Capital Letter Glottal Stop", '?'),
-    ('ॽ', "Devanagari Letter Glottal Stop", '?'),
-    ('Ꭾ', "Cherokee Letter He", '?'),
-    ('ꛫ', "Bamum Letter Ntuu", '?'),
-    ('?', "Fullwidth Question Mark", '?'),
-    ('︖', "Presentation Form For Vertical Question Mark", '?'),
-
-    ('𝅭', "Musical Symbol Combining Augmentation Dot", '.'),
-    ('․', "One Dot Leader", '.'),
-    ('܁', "Syriac Supralinear Full Stop", '.'),
-    ('܂', "Syriac Sublinear Full Stop", '.'),
-    ('꘎', "Vai Full Stop", '.'),
-    ('𐩐', "Kharoshthi Punctuation Dot", '.'),
-    ('٠', "Arabic-Indic Digit Zero", '.'),
-    ('۰', "Extended Arabic-Indic Digit Zero", '.'),
-    ('ꓸ', "Lisu Letter Tone Mya Ti", '.'),
-    ('·', "Middle Dot", '.'),
-    ('・', "Katakana Middle Dot", '.'),
-    ('・', "Halfwidth Katakana Middle Dot", '.'),
-    ('᛫', "Runic Single Punctuation", '.'),
-    ('·', "Greek Ano Teleia", '.'),
-    ('⸱', "Word Separator Middle Dot", '.'),
-    ('𐄁', "Aegean Word Separator Dot", '.'),
-    ('•', "Bullet", '.'),
-    ('‧', "Hyphenation Point", '.'),
-    ('∙', "Bullet Operator", '.'),
-    ('⋅', "Dot Operator", '.'),
-    ('ꞏ', "Latin Letter Sinological Dot", '.'),
-    ('ᐧ', "Canadian Syllabics Final Middle Dot", '.'),
-    ('ᐧ', "Canadian Syllabics Final Middle Dot", '.'),
-    ('.', "Fullwidth Full Stop", '.'),
-    ('。', "Ideographic Full Stop", '.'),
-    ('︒', "Presentation Form For Vertical Ideographic Full Stop", '.'),
-
-    ('՝', "Armenian Comma", '\''),
-    (''', "Fullwidth Apostrophe", '\''),
-    ('‘', "Left Single Quotation Mark", '\''),
-    ('’', "Right Single Quotation Mark", '\''),
-    ('‛', "Single High-Reversed-9 Quotation Mark", '\''),
-    ('′', "Prime", '\''),
-    ('‵', "Reversed Prime", '\''),
-    ('՚', "Armenian Apostrophe", '\''),
-    ('׳', "Hebrew Punctuation Geresh", '\''),
-    ('`', "Grave Accent", '\''),
-    ('`', "Greek Varia", '\''),
-    ('`', "Fullwidth Grave Accent", '\''),
-    ('´', "Acute Accent", '\''),
-    ('΄', "Greek Tonos", '\''),
-    ('´', "Greek Oxia", '\''),
-    ('᾽', "Greek Koronis", '\''),
-    ('᾿', "Greek Psili", '\''),
-    ('῾', "Greek Dasia", '\''),
-    ('ʹ', "Modifier Letter Prime", '\''),
-    ('ʹ', "Greek Numeral Sign", '\''),
-    ('ˈ', "Modifier Letter Vertical Line", '\''),
-    ('ˊ', "Modifier Letter Acute Accent", '\''),
-    ('ˋ', "Modifier Letter Grave Accent", '\''),
-    ('˴', "Modifier Letter Middle Grave Accent", '\''),
-    ('ʻ', "Modifier Letter Turned Comma", '\''),
-    ('ʽ', "Modifier Letter Reversed Comma", '\''),
-    ('ʼ', "Modifier Letter Apostrophe", '\''),
-    ('ʾ', "Modifier Letter Right Half Ring", '\''),
-    ('ꞌ', "Latin Small Letter Saltillo", '\''),
-    ('י', "Hebrew Letter Yod", '\''),
-    ('ߴ', "Nko High Tone Apostrophe", '\''),
-    ('ߵ', "Nko Low Tone Apostrophe", '\''),
-    ('ᑊ', "Canadian Syllabics West-Cree P", '\''),
-    ('ᛌ', "Runic Letter Short-Twig-Sol S", '\''),
-    ('𖽑', "Miao Sign Aspiration", '\''),
-    ('𖽒', "Miao Sign Reformed Voicing", '\''),
-
-    ('᳓', "Vedic Sign Nihshvasa", '"'),
-    ('"', "Fullwidth Quotation Mark", '"'),
-    ('“', "Left Double Quotation Mark", '"'),
-    ('”', "Right Double Quotation Mark", '"'),
-    ('‟', "Double High-Reversed-9 Quotation Mark", '"'),
-    ('″', "Double Prime", '"'),
-    ('‶', "Reversed Double Prime", '"'),
-    ('〃', "Ditto Mark", '"'),
-    ('״', "Hebrew Punctuation Gershayim", '"'),
-    ('˝', "Double Acute Accent", '"'),
-    ('ʺ', "Modifier Letter Double Prime", '"'),
-    ('˶', "Modifier Letter Middle Double Acute Accent", '"'),
-    ('˵', "Modifier Letter Middle Double Grave Accent", '"'),
-    ('ˮ', "Modifier Letter Double Apostrophe", '"'),
-    ('ײ', "Hebrew Ligature Yiddish Double Yod", '"'),
-    ('❞', "Heavy Double Comma Quotation Mark Ornament", '"'),
-    ('❝', "Heavy Double Turned Comma Quotation Mark Ornament", '"'),
-
-    ('(', "Fullwidth Left Parenthesis", '('),
-    ('❨', "Medium Left Parenthesis Ornament", '('),
-    ('﴾', "Ornate Left Parenthesis", '('),
-
-    (')', "Fullwidth Right Parenthesis", ')'),
-    ('❩', "Medium Right Parenthesis Ornament", ')'),
-    ('﴿', "Ornate Right Parenthesis", ')'),
-
-    ('[', "Fullwidth Left Square Bracket", '['),
-    ('❲', "Light Left Tortoise Shell Bracket Ornament", '['),
-    ('「', "Left Corner Bracket", '['),
-    ('『', "Left White Corner Bracket", '['),
-    ('【', "Left Black Lenticular Bracket", '['),
-    ('〔', "Left Tortoise Shell Bracket", '['),
-    ('〖', "Left White Lenticular Bracket", '['),
-    ('〘', "Left White Tortoise Shell Bracket", '['),
-    ('〚', "Left White Square Bracket", '['),
-
-    (']', "Fullwidth Right Square Bracket", ']'),
-    ('❳', "Light Right Tortoise Shell Bracket Ornament", ']'),
-    ('」', "Right Corner Bracket", ']'),
-    ('』', "Right White Corner Bracket", ']'),
-    ('】', "Right Black Lenticular Bracket", ']'),
-    ('〕', "Right Tortoise Shell Bracket", ']'),
-    ('〗', "Right White Lenticular Bracket", ']'),
-    ('〙', "Right White Tortoise Shell Bracket", ']'),
-    ('〛', "Right White Square Bracket", ']'),
-
-    ('❴', "Medium Left Curly Bracket Ornament", '{'),
-    ('𝄔', "Musical Symbol Brace", '{'),
-    ('{', "Fullwidth Left Curly Bracket", '{'),
-
-    ('❵', "Medium Right Curly Bracket Ornament", '}'),
-    ('}', "Fullwidth Right Curly Bracket", '}'),
-
-    ('⁎', "Low Asterisk", '*'),
-    ('٭', "Arabic Five Pointed Star", '*'),
-    ('∗', "Asterisk Operator", '*'),
-    ('𐌟', "Old Italic Letter Ess", '*'),
-    ('*', "Fullwidth Asterisk", '*'),
-
-    ('᜵', "Philippine Single Punctuation", '/'),
-    ('⁁', "Caret Insertion Point", '/'),
-    ('∕', "Division Slash", '/'),
-    ('⁄', "Fraction Slash", '/'),
-    ('╱', "Box Drawings Light Diagonal Upper Right To Lower Left", '/'),
-    ('⟋', "Mathematical Rising Diagonal", '/'),
-    ('⧸', "Big Solidus", '/'),
-    ('𝈺', "Greek Instrumental Notation Symbol-47", '/'),
-    ('㇓', "CJK Stroke Sp", '/'),
-    ('〳', "Vertical Kana Repeat Mark Upper Half", '/'),
-    ('Ⳇ', "Coptic Capital Letter Old Coptic Esh", '/'),
-    ('ノ', "Katakana Letter No", '/'),
-    ('丿', "CJK Unified Ideograph-4E3F", '/'),
-    ('⼃', "Kangxi Radical Slash", '/'),
-    ('/', "Fullwidth Solidus", '/'),
-
-    ('\', "Fullwidth Reverse Solidus", '\\'),
-    ('﹨', "Small Reverse Solidus", '\\'),
-    ('∖', "Set Minus", '\\'),
-    ('⟍', "Mathematical Falling Diagonal", '\\'),
-    ('⧵', "Reverse Solidus Operator", '\\'),
-    ('⧹', "Big Reverse Solidus", '\\'),
-    ('⧹', "Greek Vocal Notation Symbol-16", '\\'),
-    ('⧹', "Greek Instrumental Symbol-48", '\\'),
-    ('㇔', "CJK Stroke D", '\\'),
-    ('丶', "CJK Unified Ideograph-4E36", '\\'),
-    ('⼂', "Kangxi Radical Dot", '\\'),
-    ('、', "Ideographic Comma", '\\'),
-    ('ヽ', "Katakana Iteration Mark", '\\'),
-
-    ('ꝸ', "Latin Small Letter Um", '&'),
-    ('&', "Fullwidth Ampersand", '&'),
-
-    ('᛭', "Runic Cross Punctuation", '+'),
-    ('➕', "Heavy Plus Sign", '+'),
-    ('𐊛', "Lycian Letter H", '+'),
-    ('﬩', "Hebrew Letter Alternative Plus Sign", '+'),
-    ('+', "Fullwidth Plus Sign", '+'),
-
-    ('‹', "Single Left-Pointing Angle Quotation Mark", '<'),
-    ('❮', "Heavy Left-Pointing Angle Quotation Mark Ornament", '<'),
-    ('˂', "Modifier Letter Left Arrowhead", '<'),
-    ('𝈶', "Greek Instrumental Symbol-40", '<'),
-    ('ᐸ', "Canadian Syllabics Pa", '<'),
-    ('ᚲ', "Runic Letter Kauna", '<'),
-    ('❬', "Medium Left-Pointing Angle Bracket Ornament", '<'),
-    ('⟨', "Mathematical Left Angle Bracket", '<'),
-    ('〈', "Left-Pointing Angle Bracket", '<'),
-    ('〈', "Left Angle Bracket", '<'),
-    ('㇛', "CJK Stroke Pd", '<'),
-    ('く', "Hiragana Letter Ku", '<'),
-    ('𡿨', "CJK Unified Ideograph-21FE8", '<'),
-    ('《', "Left Double Angle Bracket", '<'),
-    ('<', "Fullwidth Less-Than Sign", '<'),
-
-    ('᐀', "Canadian Syllabics Hyphen", '='),
-    ('⹀', "Double Hyphen", '='),
-    ('゠', "Katakana-Hiragana Double Hyphen", '='),
-    ('꓿', "Lisu Punctuation Full Stop", '='),
-    ('=', "Fullwidth Equals Sign", '='),
-
-    ('›', "Single Right-Pointing Angle Quotation Mark", '>'),
-    ('❯', "Heavy Right-Pointing Angle Quotation Mark Ornament", '>'),
-    ('˃', "Modifier Letter Right Arrowhead", '>'),
-    ('𝈷', "Greek Instrumental Symbol-42", '>'),
-    ('ᐳ', "Canadian Syllabics Po", '>'),
-    ('𖼿', "Miao Letter Archaic Zza", '>'),
-    ('❭', "Medium Right-Pointing Angle Bracket Ornament", '>'),
-    ('⟩', "Mathematical Right Angle Bracket", '>'),
-    ('〉', "Right-Pointing Angle Bracket", '>'),
-    ('〉', "Right Angle Bracket", '>'),
-    ('》', "Right Double Angle Bracket", '>'),
-    ('>', "Fullwidth Greater-Than Sign", '>'),
+pub(crate) const UNICODE_ARRAY: &[(char, &str, &str)] = &[
+    ('
', "Line Separator", " "),
+    ('
', "Paragraph Separator", " "),
+    (' ', "Ogham Space mark", " "),
+    (' ', "En Quad", " "),
+    (' ', "Em Quad", " "),
+    (' ', "En Space", " "),
+    (' ', "Em Space", " "),
+    (' ', "Three-Per-Em Space", " "),
+    (' ', "Four-Per-Em Space", " "),
+    (' ', "Six-Per-Em Space", " "),
+    (' ', "Punctuation Space", " "),
+    (' ', "Thin Space", " "),
+    (' ', "Hair Space", " "),
+    (' ', "Medium Mathematical Space", " "),
+    (' ', "No-Break Space", " "),
+    (' ', "Figure Space", " "),
+    (' ', "Narrow No-Break Space", " "),
+    (' ', "Ideographic Space", " "),
+
+    ('ߺ', "Nko Lajanyalan", "_"),
+    ('﹍', "Dashed Low Line", "_"),
+    ('﹎', "Centreline Low Line", "_"),
+    ('﹏', "Wavy Low Line", "_"),
+    ('_', "Fullwidth Low Line", "_"),
+
+    ('‐', "Hyphen", "-"),
+    ('‑', "Non-Breaking Hyphen", "-"),
+    ('‒', "Figure Dash", "-"),
+    ('–', "En Dash", "-"),
+    ('—', "Em Dash", "-"),
+    ('﹘', "Small Em Dash", "-"),
+    ('۔', "Arabic Full Stop", "-"),
+    ('⁃', "Hyphen Bullet", "-"),
+    ('˗', "Modifier Letter Minus Sign", "-"),
+    ('−', "Minus Sign", "-"),
+    ('➖', "Heavy Minus Sign", "-"),
+    ('Ⲻ', "Coptic Letter Dialect-P Ni", "-"),
+    ('ー', "Katakana-Hiragana Prolonged Sound Mark", "-"),
+    ('-', "Fullwidth Hyphen-Minus", "-"),
+    ('―', "Horizontal Bar", "-"),
+    ('─', "Box Drawings Light Horizontal", "-"),
+    ('━', "Box Drawings Heavy Horizontal", "-"),
+    ('㇐', "CJK Stroke H", "-"),
+    ('ꟷ', "Latin Epigraphic Letter Sideways I", "-"),
+    ('ᅳ', "Hangul Jungseong Eu", "-"),
+    ('ㅡ', "Hangul Letter Eu", "-"),
+    ('一', "CJK Unified Ideograph-4E00", "-"),
+    ('⼀', "Kangxi Radical One", "-"),
+
+    ('؍', "Arabic Date Separator", ","),
+    ('٫', "Arabic Decimal Separator", ","),
+    ('‚', "Single Low-9 Quotation Mark", ","),
+    ('¸', "Cedilla", ","),
+    ('ꓹ', "Lisu Letter Tone Na Po", ","),
+    (',', "Fullwidth Comma", ","),
+
+    (';', "Greek Question Mark", ";"),
+    (';', "Fullwidth Semicolon", ";"),
+    ('︔', "Presentation Form For Vertical Semicolon", ";"),
+
+    ('ः', "Devanagari Sign Visarga", ":"),
+    ('ઃ', "Gujarati Sign Visarga", ":"),
+    (':', "Fullwidth Colon", ":"),
+    ('։', "Armenian Full Stop", ":"),
+    ('܃', "Syriac Supralinear Colon", ":"),
+    ('܄', "Syriac Sublinear Colon", ":"),
+    ('᛬', "Runic Multiple Punctuation", ":"),
+    ('︰', "Presentation Form For Vertical Two Dot Leader", ":"),
+    ('᠃', "Mongolian Full Stop", ":"),
+    ('᠉', "Mongolian Manchu Full Stop", ":"),
+    ('⁚', "Two Dot Punctuation", ":"),
+    ('׃', "Hebrew Punctuation Sof Pasuq", ":"),
+    ('˸', "Modifier Letter Raised Colon", ":"),
+    ('꞉', "Modifier Letter Colon", ":"),
+    ('∶', "Ratio", ":"),
+    ('ː', "Modifier Letter Triangular Colon", ":"),
+    ('ꓽ', "Lisu Letter Tone Mya Jeu", ":"),
+    ('︓', "Presentation Form For Vertical Colon", ":"),
+
+    ('!', "Fullwidth Exclamation Mark", "!"),
+    ('ǃ', "Latin Letter Retroflex Click", "!"),
+    ('ⵑ', "Tifinagh Letter Tuareg Yang", "!"),
+    ('︕', "Presentation Form For Vertical Exclamation Mark", "!"),
+
+    ('ʔ', "Latin Letter Glottal Stop", "?"),
+    ('Ɂ', "Latin Capital Letter Glottal Stop", "?"),
+    ('ॽ', "Devanagari Letter Glottal Stop", "?"),
+    ('Ꭾ', "Cherokee Letter He", "?"),
+    ('ꛫ', "Bamum Letter Ntuu", "?"),
+    ('?', "Fullwidth Question Mark", "?"),
+    ('︖', "Presentation Form For Vertical Question Mark", "?"),
+
+    ('𝅭', "Musical Symbol Combining Augmentation Dot", "."),
+    ('․', "One Dot Leader", "."),
+    ('܁', "Syriac Supralinear Full Stop", "."),
+    ('܂', "Syriac Sublinear Full Stop", "."),
+    ('꘎', "Vai Full Stop", "."),
+    ('𐩐', "Kharoshthi Punctuation Dot", "."),
+    ('٠', "Arabic-Indic Digit Zero", "."),
+    ('۰', "Extended Arabic-Indic Digit Zero", "."),
+    ('ꓸ', "Lisu Letter Tone Mya Ti", "."),
+    ('·', "Middle Dot", "."),
+    ('・', "Katakana Middle Dot", "."),
+    ('・', "Halfwidth Katakana Middle Dot", "."),
+    ('᛫', "Runic Single Punctuation", "."),
+    ('·', "Greek Ano Teleia", "."),
+    ('⸱', "Word Separator Middle Dot", "."),
+    ('𐄁', "Aegean Word Separator Dot", "."),
+    ('•', "Bullet", "."),
+    ('‧', "Hyphenation Point", "."),
+    ('∙', "Bullet Operator", "."),
+    ('⋅', "Dot Operator", "."),
+    ('ꞏ', "Latin Letter Sinological Dot", "."),
+    ('ᐧ', "Canadian Syllabics Final Middle Dot", "."),
+    ('ᐧ', "Canadian Syllabics Final Middle Dot", "."),
+    ('.', "Fullwidth Full Stop", "."),
+    ('。', "Ideographic Full Stop", "."),
+    ('︒', "Presentation Form For Vertical Ideographic Full Stop", "."),
+
+    ('՝', "Armenian Comma", "\'"),
+    (''', "Fullwidth Apostrophe", "\'"),
+    ('‘', "Left Single Quotation Mark", "\'"),
+    ('’', "Right Single Quotation Mark", "\'"),
+    ('‛', "Single High-Reversed-9 Quotation Mark", "\'"),
+    ('′', "Prime", "\'"),
+    ('‵', "Reversed Prime", "\'"),
+    ('՚', "Armenian Apostrophe", "\'"),
+    ('׳', "Hebrew Punctuation Geresh", "\'"),
+    ('`', "Grave Accent", "\'"),
+    ('`', "Greek Varia", "\'"),
+    ('`', "Fullwidth Grave Accent", "\'"),
+    ('´', "Acute Accent", "\'"),
+    ('΄', "Greek Tonos", "\'"),
+    ('´', "Greek Oxia", "\'"),
+    ('᾽', "Greek Koronis", "\'"),
+    ('᾿', "Greek Psili", "\'"),
+    ('῾', "Greek Dasia", "\'"),
+    ('ʹ', "Modifier Letter Prime", "\'"),
+    ('ʹ', "Greek Numeral Sign", "\'"),
+    ('ˈ', "Modifier Letter Vertical Line", "\'"),
+    ('ˊ', "Modifier Letter Acute Accent", "\'"),
+    ('ˋ', "Modifier Letter Grave Accent", "\'"),
+    ('˴', "Modifier Letter Middle Grave Accent", "\'"),
+    ('ʻ', "Modifier Letter Turned Comma", "\'"),
+    ('ʽ', "Modifier Letter Reversed Comma", "\'"),
+    ('ʼ', "Modifier Letter Apostrophe", "\'"),
+    ('ʾ', "Modifier Letter Right Half Ring", "\'"),
+    ('ꞌ', "Latin Small Letter Saltillo", "\'"),
+    ('י', "Hebrew Letter Yod", "\'"),
+    ('ߴ', "Nko High Tone Apostrophe", "\'"),
+    ('ߵ', "Nko Low Tone Apostrophe", "\'"),
+    ('ᑊ', "Canadian Syllabics West-Cree P", "\'"),
+    ('ᛌ', "Runic Letter Short-Twig-Sol S", "\'"),
+    ('𖽑', "Miao Sign Aspiration", "\'"),
+    ('𖽒', "Miao Sign Reformed Voicing", "\'"),
+
+    ('᳓', "Vedic Sign Nihshvasa", "\""),
+    ('"', "Fullwidth Quotation Mark", "\""),
+    ('“', "Left Double Quotation Mark", "\""),
+    ('”', "Right Double Quotation Mark", "\""),
+    ('‟', "Double High-Reversed-9 Quotation Mark", "\""),
+    ('″', "Double Prime", "\""),
+    ('‶', "Reversed Double Prime", "\""),
+    ('〃', "Ditto Mark", "\""),
+    ('״', "Hebrew Punctuation Gershayim", "\""),
+    ('˝', "Double Acute Accent", "\""),
+    ('ʺ', "Modifier Letter Double Prime", "\""),
+    ('˶', "Modifier Letter Middle Double Acute Accent", "\""),
+    ('˵', "Modifier Letter Middle Double Grave Accent", "\""),
+    ('ˮ', "Modifier Letter Double Apostrophe", "\""),
+    ('ײ', "Hebrew Ligature Yiddish Double Yod", "\""),
+    ('❞', "Heavy Double Comma Quotation Mark Ornament", "\""),
+    ('❝', "Heavy Double Turned Comma Quotation Mark Ornament", "\""),
+
+    ('(', "Fullwidth Left Parenthesis", "("),
+    ('❨', "Medium Left Parenthesis Ornament", "("),
+    ('﴾', "Ornate Left Parenthesis", "("),
+
+    (')', "Fullwidth Right Parenthesis", ")"),
+    ('❩', "Medium Right Parenthesis Ornament", ")"),
+    ('﴿', "Ornate Right Parenthesis", ")"),
+
+    ('[', "Fullwidth Left Square Bracket", "["),
+    ('❲', "Light Left Tortoise Shell Bracket Ornament", "["),
+    ('「', "Left Corner Bracket", "["),
+    ('『', "Left White Corner Bracket", "["),
+    ('【', "Left Black Lenticular Bracket", "["),
+    ('〔', "Left Tortoise Shell Bracket", "["),
+    ('〖', "Left White Lenticular Bracket", "["),
+    ('〘', "Left White Tortoise Shell Bracket", "["),
+    ('〚', "Left White Square Bracket", "["),
+
+    (']', "Fullwidth Right Square Bracket", "]"),
+    ('❳', "Light Right Tortoise Shell Bracket Ornament", "]"),
+    ('」', "Right Corner Bracket", "]"),
+    ('』', "Right White Corner Bracket", "]"),
+    ('】', "Right Black Lenticular Bracket", "]"),
+    ('〕', "Right Tortoise Shell Bracket", "]"),
+    ('〗', "Right White Lenticular Bracket", "]"),
+    ('〙', "Right White Tortoise Shell Bracket", "]"),
+    ('〛', "Right White Square Bracket", "]"),
+
+    ('❴', "Medium Left Curly Bracket Ornament", "{"),
+    ('𝄔', "Musical Symbol Brace", "{"),
+    ('{', "Fullwidth Left Curly Bracket", "{"),
+
+    ('❵', "Medium Right Curly Bracket Ornament", "}"),
+    ('}', "Fullwidth Right Curly Bracket", "}"),
+
+    ('⁎', "Low Asterisk", "*"),
+    ('٭', "Arabic Five Pointed Star", "*"),
+    ('∗', "Asterisk Operator", "*"),
+    ('𐌟', "Old Italic Letter Ess", "*"),
+    ('*', "Fullwidth Asterisk", "*"),
+
+    ('᜵', "Philippine Single Punctuation", "/"),
+    ('⁁', "Caret Insertion Point", "/"),
+    ('∕', "Division Slash", "/"),
+    ('⁄', "Fraction Slash", "/"),
+    ('╱', "Box Drawings Light Diagonal Upper Right To Lower Left", "/"),
+    ('⟋', "Mathematical Rising Diagonal", "/"),
+    ('⧸', "Big Solidus", "/"),
+    ('𝈺', "Greek Instrumental Notation Symbol-47", "/"),
+    ('㇓', "CJK Stroke Sp", "/"),
+    ('〳', "Vertical Kana Repeat Mark Upper Half", "/"),
+    ('Ⳇ', "Coptic Capital Letter Old Coptic Esh", "/"),
+    ('ノ', "Katakana Letter No", "/"),
+    ('丿', "CJK Unified Ideograph-4E3F", "/"),
+    ('⼃', "Kangxi Radical Slash", "/"),
+    ('/', "Fullwidth Solidus", "/"),
+
+    ('\', "Fullwidth Reverse Solidus", "\\"),
+    ('﹨', "Small Reverse Solidus", "\\"),
+    ('∖', "Set Minus", "\\"),
+    ('⟍', "Mathematical Falling Diagonal", "\\"),
+    ('⧵', "Reverse Solidus Operator", "\\"),
+    ('⧹', "Big Reverse Solidus", "\\"),
+    ('⧹', "Greek Vocal Notation Symbol-16", "\\"),
+    ('⧹', "Greek Instrumental Symbol-48", "\\"),
+    ('㇔', "CJK Stroke D", "\\"),
+    ('丶', "CJK Unified Ideograph-4E36", "\\"),
+    ('⼂', "Kangxi Radical Dot", "\\"),
+    ('、', "Ideographic Comma", "\\"),
+    ('ヽ', "Katakana Iteration Mark", "\\"),
+
+    ('ꝸ', "Latin Small Letter Um", "&"),
+    ('&', "Fullwidth Ampersand", "&"),
+
+    ('᛭', "Runic Cross Punctuation", "+"),
+    ('➕', "Heavy Plus Sign", "+"),
+    ('𐊛', "Lycian Letter H", "+"),
+    ('﬩', "Hebrew Letter Alternative Plus Sign", "+"),
+    ('+', "Fullwidth Plus Sign", "+"),
+
+    ('‹', "Single Left-Pointing Angle Quotation Mark", "<"),
+    ('❮', "Heavy Left-Pointing Angle Quotation Mark Ornament", "<"),
+    ('˂', "Modifier Letter Left Arrowhead", "<"),
+    ('𝈶', "Greek Instrumental Symbol-40", "<"),
+    ('ᐸ', "Canadian Syllabics Pa", "<"),
+    ('ᚲ', "Runic Letter Kauna", "<"),
+    ('❬', "Medium Left-Pointing Angle Bracket Ornament", "<"),
+    ('⟨', "Mathematical Left Angle Bracket", "<"),
+    ('〈', "Left-Pointing Angle Bracket", "<"),
+    ('〈', "Left Angle Bracket", "<"),
+    ('㇛', "CJK Stroke Pd", "<"),
+    ('く', "Hiragana Letter Ku", "<"),
+    ('𡿨', "CJK Unified Ideograph-21FE8", "<"),
+    ('《', "Left Double Angle Bracket", "<"),
+    ('<', "Fullwidth Less-Than Sign", "<"),
+
+    ('᐀', "Canadian Syllabics Hyphen", "="),
+    ('⹀', "Double Hyphen", "="),
+    ('゠', "Katakana-Hiragana Double Hyphen", "="),
+    ('꓿', "Lisu Punctuation Full Stop", "="),
+    ('=', "Fullwidth Equals Sign", "="),
+
+    ('›', "Single Right-Pointing Angle Quotation Mark", ">"),
+    ('❯', "Heavy Right-Pointing Angle Quotation Mark Ornament", ">"),
+    ('˃', "Modifier Letter Right Arrowhead", ">"),
+    ('𝈷', "Greek Instrumental Symbol-42", ">"),
+    ('ᐳ', "Canadian Syllabics Po", ">"),
+    ('𖼿', "Miao Letter Archaic Zza", ">"),
+    ('❭', "Medium Right-Pointing Angle Bracket Ornament", ">"),
+    ('⟩', "Mathematical Right Angle Bracket", ">"),
+    ('〉', "Right-Pointing Angle Bracket", ">"),
+    ('〉', "Right Angle Bracket", ">"),
+    ('》', "Right Double Angle Bracket", ">"),
+    ('>', "Fullwidth Greater-Than Sign", ">"),
+    ('⩵', "Two Consecutive Equals Signs", "==")
 ];
 
 // FIXME: the lexer could be used to turn the ASCII version of unicode homoglyphs, instead of
 // keeping the substitution token in this table. Ideally, this should be inside `rustc_lexer`.
 // However, we should first remove compound tokens like `<<` from `rustc_lexer`, and then add
 // fancier error recovery to it, as there will be less overall work to do this way.
-const ASCII_ARRAY: &[(char, &str, Option<token::TokenKind>)] = &[
-    (' ', "Space", None),
-    ('_', "Underscore", Some(token::Ident(kw::Underscore, false))),
-    ('-', "Minus/Hyphen", Some(token::BinOp(token::Minus))),
-    (',', "Comma", Some(token::Comma)),
-    (';', "Semicolon", Some(token::Semi)),
-    (':', "Colon", Some(token::Colon)),
-    ('!', "Exclamation Mark", Some(token::Not)),
-    ('?', "Question Mark", Some(token::Question)),
-    ('.', "Period", Some(token::Dot)),
-    ('(', "Left Parenthesis", Some(token::OpenDelim(Delimiter::Parenthesis))),
-    (')', "Right Parenthesis", Some(token::CloseDelim(Delimiter::Parenthesis))),
-    ('[', "Left Square Bracket", Some(token::OpenDelim(Delimiter::Bracket))),
-    (']', "Right Square Bracket", Some(token::CloseDelim(Delimiter::Bracket))),
-    ('{', "Left Curly Brace", Some(token::OpenDelim(Delimiter::Brace))),
-    ('}', "Right Curly Brace", Some(token::CloseDelim(Delimiter::Brace))),
-    ('*', "Asterisk", Some(token::BinOp(token::Star))),
-    ('/', "Slash", Some(token::BinOp(token::Slash))),
-    ('\\', "Backslash", None),
-    ('&', "Ampersand", Some(token::BinOp(token::And))),
-    ('+', "Plus Sign", Some(token::BinOp(token::Plus))),
-    ('<', "Less-Than Sign", Some(token::Lt)),
-    ('=', "Equals Sign", Some(token::Eq)),
-    ('>', "Greater-Than Sign", Some(token::Gt)),
+const ASCII_ARRAY: &[(&str, &str, Option<token::TokenKind>)] = &[
+    (" ", "Space", None),
+    ("_", "Underscore", Some(token::Ident(kw::Underscore, false))),
+    ("-", "Minus/Hyphen", Some(token::BinOp(token::Minus))),
+    (",", "Comma", Some(token::Comma)),
+    (";", "Semicolon", Some(token::Semi)),
+    (":", "Colon", Some(token::Colon)),
+    ("!", "Exclamation Mark", Some(token::Not)),
+    ("?", "Question Mark", Some(token::Question)),
+    (".", "Period", Some(token::Dot)),
+    ("(", "Left Parenthesis", Some(token::OpenDelim(Delimiter::Parenthesis))),
+    (")", "Right Parenthesis", Some(token::CloseDelim(Delimiter::Parenthesis))),
+    ("[", "Left Square Bracket", Some(token::OpenDelim(Delimiter::Bracket))),
+    ("]", "Right Square Bracket", Some(token::CloseDelim(Delimiter::Bracket))),
+    ("{", "Left Curly Brace", Some(token::OpenDelim(Delimiter::Brace))),
+    ("}", "Right Curly Brace", Some(token::CloseDelim(Delimiter::Brace))),
+    ("*", "Asterisk", Some(token::BinOp(token::Star))),
+    ("/", "Slash", Some(token::BinOp(token::Slash))),
+    ("\\", "Backslash", None),
+    ("&", "Ampersand", Some(token::BinOp(token::And))),
+    ("+", "Plus Sign", Some(token::BinOp(token::Plus))),
+    ("<", "Less-Than Sign", Some(token::Lt)),
+    ("=", "Equals Sign", Some(token::Eq)),
+    ("==", "Double Equals Sign", Some(token::EqEq)),
+    (">", "Greater-Than Sign", Some(token::Gt)),
     // FIXME: Literals are already lexed by this point, so we can't recover gracefully just by
     // spitting the correct token out.
-    ('\'', "Single Quote", None),
-    ('"', "Quotation Mark", None),
+    ("\'", "Single Quote", None),
+    ("\"", "Quotation Mark", None),
 ];
 
 pub(super) fn check_for_substitution<'a>(
@@ -337,12 +339,13 @@ pub(super) fn check_for_substitution<'a>(
     pos: BytePos,
     ch: char,
     err: &mut Diagnostic,
+    count: usize,
 ) -> Option<token::TokenKind> {
-    let &(_u_char, u_name, ascii_char) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch)?;
+    let &(_, u_name, ascii_str) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch)?;
 
-    let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8()));
+    let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8() * count));
 
-    let Some((_ascii_char, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(c, _, _)| c == ascii_char) else {
+    let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else {
         let msg = format!("substitution character not found for '{}'", ch);
         reader.sess.span_diagnostic.span_bug_no_panic(span, &msg);
         return None;
@@ -353,7 +356,7 @@ pub(super) fn check_for_substitution<'a>(
         let msg = format!(
             "Unicode characters '“' (Left Double Quotation Mark) and \
              '”' (Right Double Quotation Mark) look like '{}' ({}), but are not",
-            ascii_char, ascii_name
+            ascii_str, ascii_name
         );
         err.span_suggestion(
             Span::with_root_ctxt(
@@ -367,9 +370,14 @@ pub(super) fn check_for_substitution<'a>(
     } else {
         let msg = format!(
             "Unicode character '{}' ({}) looks like '{}' ({}), but it is not",
-            ch, u_name, ascii_char, ascii_name
+            ch, u_name, ascii_str, ascii_name
+        );
+        err.span_suggestion(
+            span,
+            &msg,
+            ascii_str.to_string().repeat(count),
+            Applicability::MaybeIncorrect,
         );
-        err.span_suggestion(span, &msg, ascii_char, Applicability::MaybeIncorrect);
     }
     token.clone()
 }
index 4c918c6702ed9b19f3a2ed08af51506c50e17666..f4c08031bcca08c15542d6eb326d56bd07e54749 100644 (file)
@@ -2353,6 +2353,28 @@ pub fn recover_const_arg(
         Err(err)
     }
 
+    /// Try to recover from an unbraced const argument whose first token [could begin a type][ty].
+    ///
+    /// [ty]: token::Token::can_begin_type
+    pub(crate) fn recover_unbraced_const_arg_that_can_begin_ty(
+        &mut self,
+        mut snapshot: SnapshotParser<'a>,
+    ) -> Option<P<ast::Expr>> {
+        match snapshot.parse_expr_res(Restrictions::CONST_EXPR, None) {
+            // Since we don't know the exact reason why we failed to parse the type or the
+            // expression, employ a simple heuristic to weed out some pathological cases.
+            Ok(expr) if let token::Comma | token::Gt = snapshot.token.kind => {
+                self.restore_snapshot(snapshot);
+                Some(expr)
+            }
+            Ok(_) => None,
+            Err(err) => {
+                err.cancel();
+                None
+            }
+        }
+    }
+
     /// Creates a dummy const argument, and reports that the expression must be enclosed in braces
     pub fn dummy_const_arg_needs_braces(
         &self,
@@ -2372,7 +2394,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 +2405,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 +2503,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 +2512,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 dd2b03988c3e8089536b1412b2cbba1e50203a3b..17d1e200b41aab6bd677a8e0c9e19d7104194056 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,
@@ -83,7 +83,7 @@ macro_rules! maybe_whole_expr {
 pub(super) enum LhsExpr {
     NotYetParsed,
     AttributesParsed(AttrWrapper),
-    AlreadyParsed(P<Expr>, bool), // (expr, starts_statement)
+    AlreadyParsed { expr: P<Expr>, starts_statement: bool },
 }
 
 impl From<Option<AttrWrapper>> for LhsExpr {
@@ -97,11 +97,11 @@ fn from(o: Option<AttrWrapper>) -> Self {
 }
 
 impl From<P<Expr>> for LhsExpr {
-    /// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed(expr)`.
+    /// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed { expr, starts_statement: false }`.
     ///
     /// This conversion does not allocate.
     fn from(expr: P<Expr>) -> Self {
-        LhsExpr::AlreadyParsed(expr, false)
+        LhsExpr::AlreadyParsed { expr, starts_statement: false }
     }
 }
 
@@ -174,7 +174,7 @@ pub(super) fn parse_assoc_expr_with(
         lhs: LhsExpr,
     ) -> PResult<'a, P<Expr>> {
         let mut starts_stmt = false;
-        let mut lhs = if let LhsExpr::AlreadyParsed(expr, starts_statement) = lhs {
+        let mut lhs = if let LhsExpr::AlreadyParsed { expr, starts_statement } = lhs {
             starts_stmt = starts_statement;
             expr
         } else {
@@ -562,17 +562,23 @@ macro_rules! make_it {
 
         // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
         match this.token.uninterpolate().kind {
-            token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)), // `!expr`
-            token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)), // `~expr`
+            // `!expr`
+            token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)),
+            // `~expr`
+            token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)),
+            // `-expr`
             token::BinOp(token::Minus) => {
                 make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Neg))
-            } // `-expr`
+            }
+            // `*expr`
             token::BinOp(token::Star) => {
                 make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Deref))
-            } // `*expr`
+            }
+            // `&expr` and `&&expr`
             token::BinOp(token::And) | token::AndAnd => {
                 make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo))
             }
+            // `+lit`
             token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
                 let mut err =
                     LeadingPlusNotSupported { span: lo, remove_plus: None, add_parentheses: None };
@@ -587,7 +593,7 @@ macro_rules! make_it {
 
                 this.bump();
                 this.parse_prefix_expr(None)
-            } // `+expr`
+            }
             // Recover from `++x`:
             token::BinOp(token::Plus)
                 if this.look_ahead(1, |t| *t == token::BinOp(token::Plus)) =>
@@ -624,7 +630,7 @@ fn parse_unary_expr(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKin
         Ok((span, self.mk_unary(op, expr)))
     }
 
-    // Recover on `!` suggesting for bitwise negation instead.
+    /// Recover on `~expr` in favor of `!expr`.
     fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
         self.sess.emit_err(TildeAsUnaryOperator(lo));
 
@@ -651,7 +657,6 @@ fn is_mistaken_not_ident_negation(&self) -> bool {
 
     /// Recover on `not expr` in favor of `!expr`.
     fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
-        // Emit the error...
         let negated_token = self.look_ahead(1, |t| t.clone());
 
         let sub_diag = if negated_token.is_numeric_lit() {
@@ -672,7 +677,6 @@ fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
             ),
         });
 
-        // ...and recover!
         self.parse_unary_expr(lo, UnOp::Not)
     }
 
@@ -1349,9 +1353,6 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
                 err.span_label(sp, "while parsing this `loop` expression");
                 err
             })
-        } else if self.eat_keyword(kw::Continue) {
-            let kind = ExprKind::Continue(self.eat_label());
-            Ok(self.mk_expr(lo.to(self.prev_token.span), kind))
         } else if self.eat_keyword(kw::Match) {
             let match_sp = self.prev_token.span;
             self.parse_match_expr().map_err(|mut err| {
@@ -1375,6 +1376,8 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
             self.parse_try_block(lo)
         } else if self.eat_keyword(kw::Return) {
             self.parse_return_expr()
+        } else if self.eat_keyword(kw::Continue) {
+            self.parse_continue_expr(lo)
         } else if self.eat_keyword(kw::Break) {
             self.parse_break_expr()
         } else if self.eat_keyword(kw::Yield) {
@@ -1471,9 +1474,8 @@ fn parse_array_or_repeat_expr(&mut self, close_delim: Delimiter) -> PResult<'a,
             } else if self.eat(&token::Comma) {
                 // Vector with two or more elements.
                 let sep = SeqSep::trailing_allowed(token::Comma);
-                let (remaining_exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
-                let mut exprs = vec![first_expr];
-                exprs.extend(remaining_exprs);
+                let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
+                exprs.insert(0, first_expr);
                 ExprKind::Array(exprs)
             } else {
                 // Vector with one element
@@ -1593,7 +1595,7 @@ fn visit_expr_post(&mut self, ex: &'ast Expr) {
                     vis.0
                 };
 
-                // Suggestion involves adding a (as of time of writing this, unstable) labeled block.
+                // Suggestion involves adding a labeled block.
                 //
                 // If there are no breaks that may use this label, suggest removing the label and
                 // recover to the unmodified expression.
@@ -1712,10 +1714,10 @@ fn parse_yeet_expr(&mut self) -> PResult<'a, P<Expr>> {
     fn parse_break_expr(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.prev_token.span;
         let mut label = self.eat_label();
-        let kind = if label.is_some() && self.token == token::Colon {
+        let kind = if self.token == token::Colon && let Some(label) = label.take() {
             // The value expression can be a labeled loop, see issue #86948, e.g.:
             // `loop { break 'label: loop { break 'label 42; }; }`
-            let lexpr = self.parse_labeled_expr(label.take().unwrap(), true)?;
+            let lexpr = self.parse_labeled_expr(label, true)?;
             self.sess.emit_err(LabeledLoopInBreak {
                 span: lexpr.span,
                 sub: WrapExpressionInParentheses {
@@ -1727,8 +1729,8 @@ fn parse_break_expr(&mut self) -> PResult<'a, P<Expr>> {
         } else if self.token != token::OpenDelim(Delimiter::Brace)
             || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
         {
-            let expr = self.parse_expr_opt()?;
-            if let Some(expr) = &expr {
+            let mut expr = self.parse_expr_opt()?;
+            if let Some(expr) = &mut expr {
                 if label.is_some()
                     && matches!(
                         expr.kind,
@@ -1746,7 +1748,19 @@ fn parse_break_expr(&mut self) -> PResult<'a, P<Expr>> {
                         BuiltinLintDiagnostics::BreakWithLabelAndLoop(expr.span),
                     );
                 }
+
+                // Recover `break label aaaaa`
+                if self.may_recover()
+                    && let ExprKind::Path(None, p) = &expr.kind
+                    && let [segment] = &*p.segments
+                    && let &ast::PathSegment { ident, args: None, .. } = segment
+                    && let Some(next) = self.parse_expr_opt()?
+                {
+                    label = Some(self.recover_ident_into_label(ident));
+                    *expr = next;
+                }
             }
+
             expr
         } else {
             None
@@ -1755,6 +1769,23 @@ fn parse_break_expr(&mut self) -> PResult<'a, P<Expr>> {
         self.maybe_recover_from_bad_qpath(expr)
     }
 
+    /// Parse `"continue" label?`.
+    fn parse_continue_expr(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
+        let mut label = self.eat_label();
+
+        // Recover `continue label` -> `continue 'label`
+        if self.may_recover()
+            && label.is_none()
+            && let Some((ident, _)) = self.token.ident()
+        {
+            self.bump();
+            label = Some(self.recover_ident_into_label(ident));
+        }
+
+        let kind = ExprKind::Continue(label);
+        Ok(self.mk_expr(lo.to(self.prev_token.span), kind))
+    }
+
     /// Parse `"yield" expr?`.
     fn parse_yield_expr(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.prev_token.span;
@@ -2220,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()))
                     },
@@ -2248,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())
             }
@@ -3043,6 +3081,25 @@ fn recover_struct_field_dots(&mut self, close_delim: Delimiter) -> bool {
         false
     }
 
+    /// Converts an ident into 'label and emits an "expected a label, found an identifier" error.
+    fn recover_ident_into_label(&mut self, ident: Ident) -> Label {
+        // Convert `label` -> `'label`,
+        // so that nameres doesn't complain about non-existing label
+        let label = format!("'{}", ident.name);
+        let ident = Ident { name: Symbol::intern(&label), span: ident.span };
+
+        self.struct_span_err(ident.span, "expected a label, found an identifier")
+            .span_suggestion(
+                ident.span,
+                "labels start with a tick",
+                label,
+                Applicability::MachineApplicable,
+            )
+            .emit();
+
+        Label { ident }
+    }
+
     /// Parses `ident (COLON expr)?`.
     fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
         let attrs = self.parse_outer_attributes()?;
@@ -3111,7 +3168,7 @@ fn mk_range(
         limits: RangeLimits,
     ) -> ExprKind {
         if end.is_none() && limits == RangeLimits::Closed {
-            self.inclusive_range_with_incorrect_end(self.prev_token.span);
+            self.inclusive_range_with_incorrect_end();
             ExprKind::Err
         } else {
             ExprKind::Range(start, end, limits)
index 2fd2a4e5154f3a98e0bd014881158a45191a7d7d..ffb23b50a160de4101fb021faff9b6af54166b4c 100644 (file)
@@ -542,9 +542,9 @@ pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, bool /* recovered */> {
         }
     }
 
-    /// Expect next token to be edible or inedible token.  If edible,
+    /// Expect next token to be edible or inedible token. If edible,
     /// then consume it; if inedible, then return without consuming
-    /// anything.  Signal a fatal error if next token is unexpected.
+    /// anything. Signal a fatal error if next token is unexpected.
     pub fn expect_one_of(
         &mut self,
         edible: &[TokenKind],
index 0b057f2f577fe73e85489bf75063576cdf3c5d72..912f7cc14f6cc238589469007013becf9d6239c2 100644 (file)
@@ -1,5 +1,7 @@
 use super::{ForceCollect, Parser, PathStyle, TrailingToken};
-use crate::errors::RemoveLet;
+use crate::errors::{
+    InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, RemoveLet,
+};
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
 use rustc_ast::ptr::P;
@@ -9,7 +11,7 @@
     PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
 };
 use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
+use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::{respan, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident};
@@ -116,7 +118,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 {
@@ -469,7 +472,7 @@ fn recover_dotdotdot_rest_pat(&mut self, lo: Span) -> PatKind {
     /// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`.
     ///
     /// Allowed binding patterns generated by `binding ::= ref? mut? $ident @ $pat_rhs`
-    /// should already have been parsed by now  at this point,
+    /// should already have been parsed by now at this point,
     /// if the next token is `@` then we can try to parse the more general form.
     ///
     /// Consult `parse_pat_ident` for the `binding` grammar.
@@ -745,47 +748,52 @@ fn parse_pat_range_begin_with(
             // Parsing e.g. `X..`.
             if let RangeEnd::Included(_) = re.node {
                 // FIXME(Centril): Consider semantic errors instead in `ast_validation`.
-                self.inclusive_range_with_incorrect_end(re.span);
+                self.inclusive_range_with_incorrect_end();
             }
             None
         };
         Ok(PatKind::Range(Some(begin), end, re))
     }
 
-    pub(super) fn inclusive_range_with_incorrect_end(&mut self, span: Span) {
+    pub(super) fn inclusive_range_with_incorrect_end(&mut self) {
         let tok = &self.token;
-
+        let span = self.prev_token.span;
         // If the user typed "..==" instead of "..=", we want to give them
         // a specific error message telling them to use "..=".
+        // If they typed "..=>", suggest they use ".. =>".
         // Otherwise, we assume that they meant to type a half open exclusive
         // range and give them an error telling them to do that instead.
-        if matches!(tok.kind, token::Eq) && tok.span.lo() == span.hi() {
-            let span_with_eq = span.to(tok.span);
+        let no_space = tok.span.lo() == span.hi();
+        match tok.kind {
+            token::Eq if no_space => {
+                let span_with_eq = span.to(tok.span);
 
-            // Ensure the user doesn't receive unhelpful unexpected token errors
-            self.bump();
-            if self.is_pat_range_end_start(0) {
-                let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
-            }
+                // Ensure the user doesn't receive unhelpful unexpected token errors
+                self.bump();
+                if self.is_pat_range_end_start(0) {
+                    let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
+                }
 
-            self.error_inclusive_range_with_extra_equals(span_with_eq);
-        } else {
-            self.error_inclusive_range_with_no_end(span);
+                self.error_inclusive_range_with_extra_equals(span_with_eq);
+            }
+            token::Gt if no_space => {
+                self.error_inclusive_range_match_arrow(span);
+            }
+            _ => self.error_inclusive_range_with_no_end(span),
         }
     }
 
     fn error_inclusive_range_with_extra_equals(&self, span: Span) {
-        self.struct_span_err(span, "unexpected `=` after inclusive range")
-            .span_suggestion_short(span, "use `..=` instead", "..=", Applicability::MaybeIncorrect)
-            .note("inclusive ranges end with a single equals sign (`..=`)")
-            .emit();
+        self.sess.emit_err(InclusiveRangeExtraEquals { span });
+    }
+
+    fn error_inclusive_range_match_arrow(&self, span: Span) {
+        let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi();
+        self.sess.emit_err(InclusiveRangeMatchArrow { span, after_pat });
     }
 
     fn error_inclusive_range_with_no_end(&self, span: Span) {
-        struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end")
-            .span_suggestion_short(span, "use `..` instead", "..", Applicability::MachineApplicable)
-            .note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")
-            .emit();
+        self.sess.emit_err(InclusiveRangeNoEnd { span });
     }
 
     /// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.
index 5333d3b8587ddaafa80c49336c50890d4f25af7a..2e706a00cf7f3babcbf027c568599a77d3431597 100644 (file)
@@ -675,22 +675,42 @@ pub(super) fn parse_generic_arg(
             GenericArg::Const(self.parse_const_arg()?)
         } else if self.check_type() {
             // Parse type argument.
-            let is_const_fn =
-                self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Parenthesis));
-            let mut snapshot = self.create_snapshot_for_diagnostic();
+
+            // Proactively create a parser snapshot enabling us to rewind and try to reparse the
+            // input as a const expression in case we fail to parse a type. If we successfully
+            // do so, we will report an error that it needs to be wrapped in braces.
+            let mut snapshot = None;
+            if self.may_recover() && self.token.can_begin_expr() {
+                snapshot = Some(self.create_snapshot_for_diagnostic());
+            }
+
             match self.parse_ty() {
-                Ok(ty) => GenericArg::Type(ty),
+                Ok(ty) => {
+                    // Since the type parser recovers from some malformed slice and array types and
+                    // successfully returns a type, we need to look for `TyKind::Err`s in the
+                    // type to determine if error recovery has occurred and if the input is not a
+                    // syntactically valid type after all.
+                    if let ast::TyKind::Slice(inner_ty) | ast::TyKind::Array(inner_ty, _) = &ty.kind
+                        && let ast::TyKind::Err = inner_ty.kind
+                        && let Some(snapshot) = snapshot
+                        && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)
+                    {
+                        return Ok(Some(self.dummy_const_arg_needs_braces(
+                            self.struct_span_err(expr.span, "invalid const generic expression"),
+                            expr.span,
+                        )));
+                    }
+
+                    GenericArg::Type(ty)
+                }
                 Err(err) => {
-                    if is_const_fn {
-                        match (*snapshot).parse_expr_res(Restrictions::CONST_EXPR, None) {
-                            Ok(expr) => {
-                                self.restore_snapshot(snapshot);
-                                return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span)));
-                            }
-                            Err(err) => {
-                                err.cancel();
-                            }
-                        }
+                    if let Some(snapshot) = snapshot
+                        && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)
+                    {
+                        return Ok(Some(self.dummy_const_arg_needs_braces(
+                            err,
+                            expr.span,
+                        )));
                     }
                     // Try to recover from possible `const` arg without braces.
                     return self.recover_const_arg(start, err).map(Some);
index 1e5c2834960352c03082ef1e40994755af26dff4..4ff9927aab51af8d3acf925aeff8ccfd6f8ba9fc 100644 (file)
@@ -164,7 +164,10 @@ fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a,
             // Perform this outside of the `collect_tokens_trailing_token` closure,
             // since our outer attributes do not apply to this part of the expression
             let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
-                this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr, true))
+                this.parse_assoc_expr_with(
+                    0,
+                    LhsExpr::AlreadyParsed { expr, starts_statement: true },
+                )
             })?;
             Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
         } else {
@@ -198,7 +201,10 @@ fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResu
             let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
             let e = self.maybe_recover_from_bad_qpath(e)?;
             let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
-            let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e, false))?;
+            let e = self.parse_assoc_expr_with(
+                0,
+                LhsExpr::AlreadyParsed { expr: e, starts_statement: false },
+            )?;
             StmtKind::Expr(e)
         };
         Ok(self.mk_stmt(lo.to(hi), kind))
index a6f702e5428694aa4077eeae5363c905674c030e..82d9138c7a331948c16e4c50bf711f558a845d33 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) }
     }
 
@@ -727,11 +786,13 @@ fn parse_generic_bounds_common(
         let mut bounds = Vec::new();
         let mut negative_bounds = Vec::new();
 
+        // In addition to looping while we find generic bounds:
+        // We continue even if we find a keyword. This is necessary for error recovery on,
+        // for example, `impl fn()`. The only keyword that can go after generic bounds is
+        // `where`, so stop if it's it.
+        // We also continue if we find types (not traits), again for error recovery.
         while self.can_begin_bound()
-            // Continue even if we find a keyword.
-            // This is necessary for error recover on, for example, `impl fn()`.
-            //
-            // The only keyword that can go after generic bounds is `where`, so stop if it's it.
+            || self.token.can_begin_type()
             || (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where))
         {
             if self.token.is_keyword(kw::Dyn) {
@@ -938,6 +999,36 @@ fn parse_generic_ty_bound(
             && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
             && let Some(path) = self.recover_path_from_fn()
         {
+            path
+        } else if !self.token.is_path_start() && self.token.can_begin_type() {
+            let ty = self.parse_ty_no_plus()?;
+            // Instead of finding a path (a trait), we found a type.
+            let mut err = self.struct_span_err(ty.span, "expected a trait, found type");
+
+            // If we can recover, try to extract a path from the type. Note
+            // that we do not use the try operator when parsing the type because
+            // if it fails then we get a parser error which we don't want (we're trying
+            // to recover from errors, not make more).
+            let path = if self.may_recover()
+                && matches!(ty.kind, TyKind::Ptr(..) | TyKind::Ref(..))
+                && let TyKind::Path(_, path) = &ty.peel_refs().kind {
+                // Just get the indirection part of the type.
+                let span = ty.span.until(path.span);
+
+                err.span_suggestion_verbose(
+                    span,
+                    "consider removing the indirection",
+                    "",
+                    Applicability::MaybeIncorrect,
+                );
+
+                path.clone()
+            } else {
+                return Err(err);
+            };
+
+            err.emit();
+
             path
         } else {
             self.parse_path(PathStyle::Type)?
@@ -957,7 +1048,7 @@ fn parse_generic_ty_bound(
                 self.parse_remaining_bounds(bounds, true)?;
                 self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
                 let sp = vec![lo, self.prev_token.span];
-                let sugg: Vec<_> = sp.iter().map(|sp| (*sp, String::new())).collect();
+                let sugg = vec![(lo, String::from(" ")), (self.prev_token.span, String::new())];
                 self.struct_span_err(sp, "incorrect braces around trait bounds")
                     .multipart_suggestion(
                         "remove the parentheses",
index 1eb227503f24236971e95f3f978f19054b7d9796..a6dfcd29762474933a31022e2f09f409d3e35865 100644 (file)
 
 pub use Alignment::*;
 pub use Count::*;
-pub use Flag::*;
 pub use Piece::*;
 pub use Position::*;
 
-use rustc_lexer::unescape;
 use std::iter;
 use std::str;
 use std::string;
@@ -112,8 +110,14 @@ pub struct FormatSpec<'a> {
     pub fill: Option<char>,
     /// Optionally specified alignment.
     pub align: Alignment,
-    /// Packed version of various flags provided.
-    pub flags: u32,
+    /// The `+` or `-` flag.
+    pub sign: Option<Sign>,
+    /// The `#` flag.
+    pub alternate: bool,
+    /// The `0` flag.
+    pub zero_pad: bool,
+    /// The `x` or `X` flag. (Only for `Debug`.)
+    pub debug_hex: Option<DebugHex>,
     /// The integer precision to use.
     pub precision: Count<'a>,
     /// The span of the precision formatting flag (for diagnostics).
@@ -163,24 +167,22 @@ pub enum Alignment {
     AlignUnknown,
 }
 
-/// Various flags which can be applied to format strings. The meaning of these
-/// flags is defined by the formatters themselves.
+/// Enum for the sign flags.
 #[derive(Copy, Clone, Debug, PartialEq)]
-pub enum Flag {
-    /// A `+` will be used to denote positive numbers.
-    FlagSignPlus,
-    /// A `-` will be used to denote negative numbers. This is the default.
-    FlagSignMinus,
-    /// An alternate form will be used for the value. In the case of numbers,
-    /// this means that the number will be prefixed with the supplied string.
-    FlagAlternate,
-    /// For numbers, this means that the number will be padded with zeroes,
-    /// and the sign (`+` or `-`) will precede them.
-    FlagSignAwareZeroPad,
-    /// For Debug / `?`, format integers in lower-case hexadecimal.
-    FlagDebugLowerHex,
-    /// For Debug / `?`, format integers in upper-case hexadecimal.
-    FlagDebugUpperHex,
+pub enum Sign {
+    /// The `+` flag.
+    Plus,
+    /// The `-` flag.
+    Minus,
+}
+
+/// Enum for the debug hex flags.
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum DebugHex {
+    /// The `x` flag in `{:x?}`.
+    Lower,
+    /// The `X` flag in `{:X?}`.
+    Upper,
 }
 
 /// A count is used for the precision and width parameters of an integer, and
@@ -314,11 +316,12 @@ pub fn new(
         append_newline: bool,
         mode: ParseMode,
     ) -> Parser<'a> {
-        let input_string_kind = find_width_map_from_snippet(s, snippet, style);
+        let input_string_kind = find_width_map_from_snippet(snippet, style);
         let (width_map, is_literal) = match input_string_kind {
             InputStringKind::Literal { width_mappings } => (width_mappings, true),
             InputStringKind::NotALiteral => (Vec::new(), false),
         };
+
         Parser {
             mode,
             input: s,
@@ -597,7 +600,10 @@ fn format(&mut self) -> FormatSpec<'a> {
         let mut spec = FormatSpec {
             fill: None,
             align: AlignUnknown,
-            flags: 0,
+            sign: None,
+            alternate: false,
+            zero_pad: false,
+            debug_hex: None,
             precision: CountImplied,
             precision_span: None,
             width: CountImplied,
@@ -626,13 +632,13 @@ fn format(&mut self) -> FormatSpec<'a> {
         }
         // Sign flags
         if self.consume('+') {
-            spec.flags |= 1 << (FlagSignPlus as u32);
+            spec.sign = Some(Sign::Plus);
         } else if self.consume('-') {
-            spec.flags |= 1 << (FlagSignMinus as u32);
+            spec.sign = Some(Sign::Minus);
         }
         // Alternate marker
         if self.consume('#') {
-            spec.flags |= 1 << (FlagAlternate as u32);
+            spec.alternate = true;
         }
         // Width and precision
         let mut havewidth = false;
@@ -647,7 +653,7 @@ fn format(&mut self) -> FormatSpec<'a> {
                 spec.width_span = Some(self.span(end - 1, end + 1));
                 havewidth = true;
             } else {
-                spec.flags |= 1 << (FlagSignAwareZeroPad as u32);
+                spec.zero_pad = true;
             }
         }
 
@@ -678,14 +684,14 @@ fn format(&mut self) -> FormatSpec<'a> {
         // Optional radix followed by the actual format specifier
         if self.consume('x') {
             if self.consume('?') {
-                spec.flags |= 1 << (FlagDebugLowerHex as u32);
+                spec.debug_hex = Some(DebugHex::Lower);
                 spec.ty = "?";
             } else {
                 spec.ty = "x";
             }
         } else if self.consume('X') {
             if self.consume('?') {
-                spec.flags |= 1 << (FlagDebugUpperHex as u32);
+                spec.debug_hex = Some(DebugHex::Upper);
                 spec.ty = "?";
             } else {
                 spec.ty = "X";
@@ -708,7 +714,10 @@ fn inline_asm(&mut self) -> FormatSpec<'a> {
         let mut spec = FormatSpec {
             fill: None,
             align: AlignUnknown,
-            flags: 0,
+            sign: None,
+            alternate: false,
+            zero_pad: false,
+            debug_hex: None,
             precision: CountImplied,
             precision_span: None,
             width: CountImplied,
@@ -856,7 +865,6 @@ fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>)
 /// written code (code snippet) and the `InternedString` that gets processed in the `Parser`
 /// in order to properly synthesise the intra-string `Span`s for error diagnostics.
 fn find_width_map_from_snippet(
-    input: &str,
     snippet: Option<string::String>,
     str_style: Option<usize>,
 ) -> InputStringKind {
@@ -869,27 +877,8 @@ fn find_width_map_from_snippet(
         return InputStringKind::Literal { width_mappings: Vec::new() };
     }
 
-    // Strip quotes.
     let snippet = &snippet[1..snippet.len() - 1];
 
-    // Macros like `println` add a newline at the end. That technically doens't make them "literals" anymore, but it's fine
-    // since we will never need to point our spans there, so we lie about it here by ignoring it.
-    // Since there might actually be newlines in the source code, we need to normalize away all trailing newlines.
-    // If we only trimmed it off the input, `format!("\n")` would cause a mismatch as here we they actually match up.
-    // Alternatively, we could just count the trailing newlines and only trim one from the input if they don't match up.
-    let input_no_nl = input.trim_end_matches('\n');
-    let Ok(unescaped) = unescape_string(snippet) else {
-        return InputStringKind::NotALiteral;
-    };
-
-    let unescaped_no_nl = unescaped.trim_end_matches('\n');
-
-    if unescaped_no_nl != input_no_nl {
-        // The source string that we're pointing at isn't our input, so spans pointing at it will be incorrect.
-        // This can for example happen with proc macros that respan generated literals.
-        return InputStringKind::NotALiteral;
-    }
-
     let mut s = snippet.char_indices();
     let mut width_mappings = vec![];
     while let Some((pos, c)) = s.next() {
@@ -972,19 +961,6 @@ fn find_width_map_from_snippet(
     InputStringKind::Literal { width_mappings }
 }
 
-fn unescape_string(string: &str) -> Result<string::String, unescape::EscapeError> {
-    let mut buf = string::String::new();
-    let mut error = Ok(());
-    unescape::unescape_literal(string, unescape::Mode::Str, &mut |_, unescaped_char| {
-        match unescaped_char {
-            Ok(c) => buf.push(c),
-            Err(err) => error = Err(err),
-        }
-    });
-
-    error.map(|_| buf)
-}
-
 // Assert a reasonable size for `Piece`
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Piece<'_>, 16);
index 2992ba845ab16aab0b3da5da04096c2978ce9900..45314e2fb5500ec4ebd395719e00d7ba68044a98 100644 (file)
@@ -10,7 +10,10 @@ fn fmtdflt() -> FormatSpec<'static> {
     return FormatSpec {
         fill: None,
         align: AlignUnknown,
-        flags: 0,
+        sign: None,
+        alternate: false,
+        zero_pad: false,
+        debug_hex: None,
         precision: CountImplied,
         width: CountImplied,
         precision_span: None,
@@ -126,7 +129,10 @@ fn format_type() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 width: CountImplied,
                 precision_span: None,
@@ -147,7 +153,10 @@ fn format_align_fill() {
             format: FormatSpec {
                 fill: None,
                 align: AlignRight,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 width: CountImplied,
                 precision_span: None,
@@ -165,7 +174,10 @@ fn format_align_fill() {
             format: FormatSpec {
                 fill: Some('0'),
                 align: AlignLeft,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 width: CountImplied,
                 precision_span: None,
@@ -183,7 +195,10 @@ fn format_align_fill() {
             format: FormatSpec {
                 fill: Some('*'),
                 align: AlignLeft,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 width: CountImplied,
                 precision_span: None,
@@ -204,7 +219,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 precision_span: None,
                 width: CountIs(10),
@@ -222,7 +240,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountIs(10),
                 precision_span: Some(InnerSpan { start: 6, end: 9 }),
                 width: CountIsParam(10),
@@ -240,7 +261,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountIs(10),
                 precision_span: Some(InnerSpan { start: 6, end: 9 }),
                 width: CountIsParam(0),
@@ -258,7 +282,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountIsStar(0),
                 precision_span: Some(InnerSpan { start: 3, end: 5 }),
                 width: CountImplied,
@@ -276,7 +303,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountIsParam(10),
                 width: CountImplied,
                 precision_span: Some(InnerSpan::new(3, 7)),
@@ -294,7 +324,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountIsName("b", InnerSpan { start: 6, end: 7 }),
                 precision_span: Some(InnerSpan { start: 5, end: 8 }),
                 width: CountIsName("a", InnerSpan { start: 3, end: 4 }),
@@ -312,7 +345,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountIs(4),
                 precision_span: Some(InnerSpan { start: 3, end: 5 }),
                 width: CountImplied,
@@ -333,7 +369,10 @@ fn format_flags() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: (1 << FlagSignMinus as u32),
+                sign: Some(Sign::Minus),
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 width: CountImplied,
                 precision_span: None,
@@ -351,7 +390,10 @@ fn format_flags() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32),
+                sign: Some(Sign::Plus),
+                alternate: true,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 width: CountImplied,
                 precision_span: None,
@@ -374,7 +416,10 @@ fn format_mixture() {
                 format: FormatSpec {
                     fill: None,
                     align: AlignUnknown,
-                    flags: 0,
+                    sign: None,
+                    alternate: false,
+                    zero_pad: false,
+                    debug_hex: None,
                     precision: CountImplied,
                     width: CountImplied,
                     precision_span: None,
index f9f9799d3e4f2058bf9911a23a60c22d9cf2837f..25cc65ba04c8b7ca083695b7426179bf41208939 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)
+                }
                 _ => {}
             }
 
@@ -419,7 +453,9 @@ fn check_cmse_nonsecure_entry(
     /// Debugging aid for `object_lifetime_default` query.
     fn check_object_lifetime_default(&self, hir_id: HirId) {
         let tcx = self.tcx;
-        if let Some(generics) = tcx.hir().get_generics(tcx.hir().local_def_id(hir_id)) {
+        if let Some(owner_id) = hir_id.as_owner()
+            && let Some(generics) = tcx.hir().get_generics(owner_id.def_id)
+        {
             for p in generics.params {
                 let hir::GenericParamKind::Type { .. } = p.kind else { continue };
                 let default = tcx.object_lifetime_default(p.def_id);
@@ -1909,7 +1945,7 @@ fn check_rustc_allow_const_fn_unstable(
     ) -> bool {
         match target {
             Target::Fn | Target::Method(_)
-                if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id).to_def_id()) =>
+                if self.tcx.is_const_fn_raw(hir_id.expect_owner().to_def_id()) =>
             {
                 true
             }
@@ -2063,6 +2099,104 @@ 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).subst_identity());
+            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 +2359,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 edb0e4367f27354114415fa2dccac4ba576a1af8..127acb46e9242c36de20f6d42ddb098020d5445c 100644 (file)
@@ -266,7 +266,7 @@ fn should_ignore_item(&mut self, def_id: DefId) -> bool {
             if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
                 && self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
             {
-                let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
+                let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap().subst_identity();
                 if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind()
                     && let Some(adt_def_id) = adt_def.did().as_local()
                 {
@@ -451,29 +451,23 @@ fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
         // referenced by it should be considered as used.
         let in_pat = mem::replace(&mut self.in_pat, false);
 
-        self.live_symbols.insert(self.tcx.hir().local_def_id(c.hir_id));
+        self.live_symbols.insert(c.def_id);
         intravisit::walk_anon_const(self, c);
 
         self.in_pat = in_pat;
     }
 }
 
-fn has_allow_dead_code_or_lang_attr_helper(
-    tcx: TyCtxt<'_>,
-    id: hir::HirId,
-    lint: &'static lint::Lint,
-) -> bool {
-    let attrs = tcx.hir().attrs(id);
-    if tcx.sess.contains_name(attrs, sym::lang) {
+fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+    if tcx.has_attr(def_id.to_def_id(), sym::lang) {
         return true;
     }
 
     // Stable attribute for #[lang = "panic_impl"]
-    if tcx.sess.contains_name(attrs, sym::panic_handler) {
+    if tcx.has_attr(def_id.to_def_id(), sym::panic_handler) {
         return true;
     }
 
-    let def_id = tcx.hir().local_def_id(id);
     if tcx.def_kind(def_id).has_codegen_attrs() {
         let cg_attrs = tcx.codegen_fn_attrs(def_id);
 
@@ -487,11 +481,8 @@ fn has_allow_dead_code_or_lang_attr_helper(
         }
     }
 
-    tcx.lint_level_at_node(lint, id).0 == lint::Allow
-}
-
-fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
-    has_allow_dead_code_or_lang_attr_helper(tcx, id, lint::builtin::DEAD_CODE)
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+    tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0 == lint::Allow
 }
 
 // These check_* functions seeds items that
@@ -513,7 +504,7 @@ fn check_item<'tcx>(
     struct_constructors: &mut FxHashMap<LocalDefId, LocalDefId>,
     id: hir::ItemId,
 ) {
-    let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.hir_id());
+    let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.owner_id.def_id);
     if allow_dead_code {
         worklist.push(id.owner_id.def_id);
     }
@@ -548,9 +539,7 @@ fn check_item<'tcx>(
 
             // And we access the Map here to get HirId from LocalDefId
             for id in local_def_ids {
-                if of_trait.is_some()
-                    || has_allow_dead_code_or_lang_attr(tcx, tcx.hir().local_def_id_to_hir_id(id))
-                {
+                if of_trait.is_some() || has_allow_dead_code_or_lang_attr(tcx, id) {
                     worklist.push(id);
                 }
             }
@@ -558,9 +547,9 @@ fn check_item<'tcx>(
         DefKind::Struct => {
             let item = tcx.hir().item(id);
             if let hir::ItemKind::Struct(ref variant_data, _) = item.kind
-                && let Some(ctor_hir_id) = variant_data.ctor_hir_id()
+                && let Some(ctor_def_id) = variant_data.ctor_def_id()
             {
-                struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.owner_id.def_id);
+                struct_constructors.insert(ctor_def_id, item.owner_id.def_id);
             }
         }
         DefKind::GlobalAsm => {
@@ -576,7 +565,7 @@ fn check_trait_item(tcx: TyCtxt<'_>, worklist: &mut Vec<LocalDefId>, id: hir::Tr
     if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) {
         let trait_item = tcx.hir().trait_item(id);
         if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
-            && has_allow_dead_code_or_lang_attr(tcx, trait_item.hir_id())
+            && has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id)
         {
             worklist.push(trait_item.owner_id.def_id);
         }
@@ -585,7 +574,7 @@ fn check_trait_item(tcx: TyCtxt<'_>, worklist: &mut Vec<LocalDefId>, id: hir::Tr
 
 fn check_foreign_item(tcx: TyCtxt<'_>, worklist: &mut Vec<LocalDefId>, id: hir::ForeignItemId) {
     if matches!(tcx.def_kind(id.owner_id), DefKind::Static(_) | DefKind::Fn)
-        && has_allow_dead_code_or_lang_attr(tcx, id.hir_id())
+        && has_allow_dead_code_or_lang_attr(tcx, id.owner_id.def_id)
     {
         worklist.push(id.owner_id.def_id);
     }
@@ -806,8 +795,7 @@ fn check_definition(&mut self, def_id: LocalDefId) {
         if self.live_symbols.contains(&def_id) {
             return;
         }
-        let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-        if has_allow_dead_code_or_lang_attr(self.tcx, hir_id) {
+        if has_allow_dead_code_or_lang_attr(self.tcx, def_id) {
             return;
         }
         let Some(name) = self.tcx.opt_item_name(def_id.to_def_id()) else {
index 5885f45ae45db788642b311f7245a98e8d70fcd3..b327ba63330ba8044ddd15daa4bc110a3ab9e023 100644 (file)
@@ -195,7 +195,7 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
 
     // There is no main function.
     let mut has_filename = true;
-    let filename = tcx.sess.local_crate_source_file.clone().unwrap_or_else(|| {
+    let filename = tcx.sess.local_crate_source_file().unwrap_or_else(|| {
         has_filename = false;
         Default::default()
     });
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..51a19c8e3c02ba227bfdb3b792c208a5ada546e0 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::util::common::to_readable_str;
+use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
@@ -363,7 +364,7 @@ fn visit_fn(
         fd: &'v hir::FnDecl<'v>,
         b: hir::BodyId,
         _: Span,
-        id: hir::HirId,
+        id: LocalDefId,
     ) {
         self.record("FnDecl", Id::None, fd);
         hir_visit::walk_fn(self, fk, fd, b, id)
@@ -567,7 +568,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 9a40b847d8552ebd9800fa42f6a6791b17562f73..fdd0e5dab705cb17691d0a45b489f6d54dbcaf1c 100644 (file)
@@ -15,9 +15,9 @@
 
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::{extract, GenericRequirement};
-use rustc_hir::{HirId, LangItem, LanguageItems, Target};
+use rustc_hir::{LangItem, LanguageItems, Target};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::cstore::ExternCrate;
 use rustc_span::{symbol::kw::Empty, Span};
@@ -40,13 +40,13 @@ fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
         LanguageItemCollector { tcx, items: LanguageItems::new() }
     }
 
-    fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
-        let attrs = self.tcx.hir().attrs(hir_id);
+    fn check_for_lang(&mut self, actual_target: Target, def_id: LocalDefId) {
+        let attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id));
         if let Some((name, span)) = extract(&attrs) {
             match LangItem::from_name(name) {
                 // Known lang item with attribute on correct target.
                 Some(lang_item) if actual_target == lang_item.target() => {
-                    self.collect_item_extended(lang_item, hir_id, span);
+                    self.collect_item_extended(lang_item, def_id, span);
                 }
                 // Known lang item with attribute on incorrect target.
                 Some(lang_item) => {
@@ -142,8 +142,7 @@ fn collect_item(&mut self, lang_item: LangItem, item_def_id: DefId) {
 
     // Like collect_item() above, but also checks whether the lang item is declared
     // with the right number of generic arguments.
-    fn collect_item_extended(&mut self, lang_item: LangItem, hir_id: HirId, span: Span) {
-        let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
+    fn collect_item_extended(&mut self, lang_item: LangItem, item_def_id: LocalDefId, span: Span) {
         let name = lang_item.name();
 
         // Now check whether the lang_item has the expected number of generic
@@ -154,7 +153,8 @@ fn collect_item_extended(&mut self, lang_item: LangItem, hir_id: HirId, span: Sp
         // Some other types like Box and various functions like drop_in_place
         // have minimum requirements.
 
-        if let hir::Node::Item(hir::Item { kind, span: item_span, .. }) = self.tcx.hir().get(hir_id)
+        if let hir::Node::Item(hir::Item { kind, span: item_span, .. }) =
+            self.tcx.hir().get_by_def_id(item_def_id)
         {
             let (actual_num, generics_span) = match kind.generics() {
                 Some(generics) => (generics.params.len(), generics.span),
@@ -191,7 +191,7 @@ fn collect_item_extended(&mut self, lang_item: LangItem, hir_id: HirId, span: Sp
             }
         }
 
-        self.collect_item(lang_item, item_def_id);
+        self.collect_item(lang_item, item_def_id.to_def_id());
     }
 }
 
@@ -211,13 +211,14 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems {
     let crate_items = tcx.hir_crate_items(());
 
     for id in crate_items.items() {
-        collector.check_for_lang(Target::from_def_kind(tcx.def_kind(id.owner_id)), id.hir_id());
+        collector
+            .check_for_lang(Target::from_def_kind(tcx.def_kind(id.owner_id)), id.owner_id.def_id);
 
         if matches!(tcx.def_kind(id.owner_id), DefKind::Enum) {
             let item = tcx.hir().item(id);
             if let hir::ItemKind::Enum(def, ..) = &item.kind {
                 for variant in def.variants {
-                    collector.check_for_lang(Target::Variant, variant.hir_id);
+                    collector.check_for_lang(Target::Variant, variant.def_id);
                 }
             }
         }
@@ -226,13 +227,13 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems {
     // FIXME: avoid calling trait_item() when possible
     for id in crate_items.trait_items() {
         let item = tcx.hir().trait_item(id);
-        collector.check_for_lang(Target::from_trait_item(item), item.hir_id())
+        collector.check_for_lang(Target::from_trait_item(item), item.owner_id.def_id)
     }
 
     // FIXME: avoid calling impl_item() when possible
     for id in crate_items.impl_items() {
         let item = tcx.hir().impl_item(id);
-        collector.check_for_lang(target_from_impl_item(tcx, item), item.hir_id())
+        collector.check_for_lang(target_from_impl_item(tcx, item), item.owner_id.def_id)
     }
 
     // Extract out the found lang items.
index b5843c0ae488b1f17c58d81c1ae91758baf4e8e7..4c6a9b23fdf12a9ed33c99f71337ce81c64364d0 100644 (file)
@@ -137,6 +137,12 @@ fn visit_attribute(&mut self, attr: &'tcx Attribute) {
 }
 
 fn lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures {
+    // If `staged_api` is not enabled then we aren't allowed to define lib
+    // features; there is no point collecting them.
+    if !tcx.features().staged_api {
+        return new_lib_features();
+    }
+
     let mut collector = LibFeatureCollector::new(tcx);
     tcx.hir().walk_attributes(&mut collector);
     collector.lib_features
index b49432b79962bd3c288ec770a85fe2d1d1e5483c..6afdcc37fe86ea9d15652bcd848aec739c6ad4b8 100644 (file)
@@ -191,9 +191,9 @@ pub fn provide(providers: &mut Providers) {
 // Creating ir_maps
 //
 // This is the first pass and the one that drives the main
-// computation.  It walks up and down the IR once.  On the way down,
+// computation. It walks up and down the IR once. On the way down,
 // we count for each function the number of variables as well as
-// liveness nodes.  A liveness node is basically an expression or
+// liveness nodes. A liveness node is basically an expression or
 // capture clause that does something of interest: either it has
 // interesting control flow or it uses/defines a local variable.
 //
@@ -203,11 +203,11 @@ pub fn provide(providers: &mut Providers) {
 // of live variables at each program point.
 //
 // Finally, we run back over the IR one last time and, using the
-// computed liveness, check various safety conditions.  For example,
+// computed liveness, check various safety conditions. For example,
 // there must be no live nodes at the definition site for a variable
-// unless it has an initializer.  Similarly, each non-mutable local
+// unless it has an initializer. Similarly, each non-mutable local
 // variable must not be assigned if there is some successor
-// assignment.  And so forth.
+// assignment. And so forth.
 
 struct CaptureInfo {
     ln: LiveNode,
@@ -417,7 +417,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
                 self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id));
 
                 // Make a live_node for each mentioned variable, with the span
-                // being the location that the variable is used.  This results
+                // being the location that the variable is used. This results
                 // in better error messages than just pointing at the closure
                 // construction site.
                 let mut call_caps = Vec::new();
@@ -792,7 +792,7 @@ fn propagate_through_stmt(&mut self, stmt: &hir::Stmt<'_>, succ: LiveNode) -> Li
         match stmt.kind {
             hir::StmtKind::Local(ref local) => {
                 // Note: we mark the variable as defined regardless of whether
-                // there is an initializer.  Initially I had thought to only mark
+                // there is an initializer. Initially I had thought to only mark
                 // the live variable as defined if it was initialized, and then we
                 // could check for uninit variables just by scanning what is live
                 // at the start of the function. But that doesn't work so well for
@@ -1169,24 +1169,24 @@ fn propagate_through_place_components(&mut self, expr: &Expr<'_>, succ: LiveNode
         //
         // # Tracked places
         //
-        // A tracked place is a local variable/argument `x`.  In
+        // A tracked place is a local variable/argument `x`. In
         // these cases, the link_node where the write occurs is linked
-        // to node id of `x`.  The `write_place()` routine generates
-        // the contents of this node.  There are no subcomponents to
+        // to node id of `x`. The `write_place()` routine generates
+        // the contents of this node. There are no subcomponents to
         // consider.
         //
         // # Non-tracked places
         //
-        // These are places like `x[5]` or `x.f`.  In that case, we
+        // These are places like `x[5]` or `x.f`. In that case, we
         // basically ignore the value which is written to but generate
-        // reads for the components---`x` in these two examples.  The
+        // reads for the components---`x` in these two examples. The
         // components reads are generated by
         // `propagate_through_place_components()` (this fn).
         //
         // # Illegal places
         //
         // It is still possible to observe assignments to non-places;
-        // these errors are detected in the later pass borrowck.  We
+        // these errors are detected in the later pass borrowck. We
         // just ignore such cases and treat them as reads.
 
         match expr.kind {
@@ -1204,7 +1204,7 @@ fn write_place(&mut self, expr: &Expr<'_>, succ: LiveNode, acc: u32) -> LiveNode
             }
 
             // We do not track other places, so just propagate through
-            // to their subcomponents.  Also, it may happen that
+            // to their subcomponents. Also, it may happen that
             // non-places occur here, because those are detected in the
             // later pass borrowck.
             _ => succ,
index 96f7236de5cb12ab9209f1b2827319026419cfaf..0bde7502e3991665a0af77a14c9552e2edcb618e 100644 (file)
@@ -147,7 +147,7 @@ fn annotate<F>(
         }
 
         if !self.tcx.features().staged_api {
-            // Propagate unstability.  This can happen even for non-staged-api crates in case
+            // Propagate unstability. This can happen even for non-staged-api crates in case
             // -Zforce-unstable-if-unmarked is set.
             if let Some(stab) = self.parent_stab {
                 if inherit_deprecation.yes() && stab.is_unstable() {
@@ -855,7 +855,8 @@ fn visit_path(&mut self, path: &hir::Path<'tcx>, id: hir::HirId) {
 /// See issue #94972 for details on why this is a special case
 fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
     // Get the LocalDefId so we can lookup the item to check the kind.
-    let Some(def_id) = tcx.hir().opt_local_def_id(id) else { return false; };
+    let Some(owner) = id.as_owner() else { return false; };
+    let def_id = owner.def_id;
 
     let Some(stab) = tcx.stability().local_stability(def_id) else {
         return false;
index 564cb1baa690914fca320ceb77a56a07e17b5706..43552861532235ef5c78d931a75bcf2f9f27b2d1 100644 (file)
@@ -1,6 +1,5 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(associated_type_defaults)]
-#![feature(control_flow_enum)]
 #![feature(rustc_private)]
 #![feature(try_blocks)]
 #![feature(let_chains)]
@@ -19,7 +18,7 @@
 use rustc_data_structures::intern::Interned;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind};
 use rustc_middle::bug;
@@ -112,7 +111,11 @@ impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V>
     fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<V::BreakTy> {
         let TraitRef { def_id, substs, .. } = trait_ref;
         self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?;
-        if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
+        if self.def_id_visitor.shallow() {
+            ControlFlow::Continue(())
+        } else {
+            substs.visit_with(self)
+        }
     }
 
     fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow<V::BreakTy> {
@@ -131,7 +134,7 @@ fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow<
             };
         self.visit_trait(trait_ref)?;
         if self.def_id_visitor.shallow() {
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         } else {
             assoc_substs.iter().try_for_each(|subst| subst.visit_with(self))
         }
@@ -155,7 +158,7 @@ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::
                 ty,
                 _region,
             ))) => ty.visit_with(self),
-            ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => ControlFlow::CONTINUE,
+            ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => ControlFlow::Continue(()),
             ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self),
             ty::PredicateKind::WellFormed(arg) => arg.visit_with(self),
             _ => bug!("unexpected predicate: {:?}", predicate),
@@ -189,13 +192,14 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
             | ty::Generator(def_id, ..) => {
                 self.def_id_visitor.visit_def_id(def_id, "type", &ty)?;
                 if self.def_id_visitor.shallow() {
-                    return ControlFlow::CONTINUE;
+                    return ControlFlow::Continue(());
                 }
                 // Default type visitor doesn't visit signatures of fn types.
                 // Something like `fn() -> Priv {my_func}` is considered a private type even if
                 // `my_func` is public, so we need to visit signatures.
                 if let ty::FnDef(..) = ty.kind() {
-                    tcx.fn_sig(def_id).visit_with(self)?;
+                    // FIXME: this should probably use `substs` from `FnDef`
+                    tcx.fn_sig(def_id).subst_identity().visit_with(self)?;
                 }
                 // Inherent static methods don't have self type in substs.
                 // Something like `fn() {my_method}` type of the method
@@ -214,7 +218,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
                     // as visible/reachable even if both `Type` and `Trait` are private.
                     // Ideally, associated types should be substituted in the same way as
                     // free type aliases, but this isn't done yet.
-                    return ControlFlow::CONTINUE;
+                    return ControlFlow::Continue(());
                 }
                 // This will also visit substs if necessary, so we don't need to recurse.
                 return self.visit_projection_ty(proj);
@@ -267,14 +271,15 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
             | ty::FnPtr(..)
             | ty::Param(..)
             | ty::Error(_)
-            | ty::GeneratorWitness(..) => {}
+            | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..) => {}
             ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => {
                 bug!("unexpected type: {:?}", ty)
             }
         }
 
         if self.def_id_visitor.shallow() {
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         } else {
             ty.super_visit_with(self)
         }
@@ -319,7 +324,7 @@ fn visit_def_id(
         if let Some(def_id) = def_id.as_local() {
             self.min = VL::new_min(self, def_id);
         }
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 }
 
@@ -338,7 +343,7 @@ fn of_impl(
         let mut find = FindMin { tcx, effective_visibilities, min: Self::MAX };
         find.visit(tcx.type_of(def_id));
         if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
-            find.visit_trait(trait_ref);
+            find.visit_trait(trait_ref.subst_identity());
         }
         find.min
     }
@@ -838,7 +843,7 @@ fn generics(&mut self) -> &mut Self {
                 GenericParamDefKind::Const { has_default } => {
                     self.visit(self.ev.tcx.type_of(param.def_id));
                     if has_default {
-                        self.visit(self.ev.tcx.const_param_default(param.def_id));
+                        self.visit(self.ev.tcx.const_param_default(param.def_id).subst_identity());
                     }
                 }
             }
@@ -858,7 +863,7 @@ fn ty(&mut self) -> &mut Self {
 
     fn trait_ref(&mut self) -> &mut Self {
         if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
-            self.visit_trait(trait_ref);
+            self.visit_trait(trait_ref.subst_identity());
         }
         self
     }
@@ -881,7 +886,7 @@ fn visit_def_id(
                 self.ev.update(def_id, self.level);
             }
         }
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 }
 
@@ -1368,9 +1373,9 @@ fn visit_def_id(
         descr: &dyn fmt::Display,
     ) -> ControlFlow<Self::BreakTy> {
         if self.check_def_id(def_id, kind, descr) {
-            ControlFlow::BREAK
+            ControlFlow::Break(())
         } else {
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         }
     }
 }
@@ -1865,16 +1870,16 @@ fn visit_def_id(
         descr: &dyn fmt::Display,
     ) -> ControlFlow<Self::BreakTy> {
         if self.check_def_id(def_id, kind, descr) {
-            ControlFlow::BREAK
+            ControlFlow::Break(())
         } else {
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         }
     }
 }
 
 struct PrivateItemsInPublicInterfacesChecker<'tcx> {
     tcx: TyCtxt<'tcx>,
-    old_error_set_ancestry: LocalDefIdSet,
+    old_error_set_ancestry: HirIdSet,
 }
 
 impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
@@ -1887,7 +1892,9 @@ fn check(
             tcx: self.tcx,
             item_def_id: def_id,
             required_visibility,
-            has_old_errors: self.old_error_set_ancestry.contains(&def_id),
+            has_old_errors: self
+                .old_error_set_ancestry
+                .contains(&self.tcx.hir().local_def_id_to_hir_id(def_id)),
             in_assoc_ty: false,
         }
     }
@@ -2153,15 +2160,7 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
     }
 
     // Check for private types and traits in public interfaces.
-    let mut checker = PrivateItemsInPublicInterfacesChecker {
-        tcx,
-        // Only definition IDs are ever searched in `old_error_set_ancestry`,
-        // so we can filter away all non-definition IDs at this point.
-        old_error_set_ancestry: old_error_set_ancestry
-            .into_iter()
-            .filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id))
-            .collect(),
-    };
+    let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, old_error_set_ancestry };
 
     for id in tcx.hir().items() {
         checker.check_item(id);
index 53c9da15737183b0120bce2be2d1667e9bb364da..47b2fd8f8f47a4d31da672b7e76c5de3b69d5d2f 100644 (file)
@@ -490,8 +490,8 @@ pub fn read_index(&self, dep_node_index: DepNodeIndex) {
     /// This is used to remove cycles during type-checking const generic parameters.
     ///
     /// As usual in the query system, we consider the current state of the calling query
-    /// only depends on the list of dependencies up to now.  As a consequence, the value
-    /// that this query gives us can only depend on those dependencies too.  Therefore,
+    /// only depends on the list of dependencies up to now. As a consequence, the value
+    /// that this query gives us can only depend on those dependencies too. Therefore,
     /// it is sound to use the current dependency set for the created node.
     ///
     /// During replay, the order of the nodes is relevant in the dependency graph.
@@ -510,9 +510,9 @@ pub fn with_feed_task<Ctxt: DepContext<DepKind = K>, A: Debug, R: Debug>(
         hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
     ) -> DepNodeIndex {
         if let Some(data) = self.data.as_ref() {
-            // The caller query has more dependencies than the node we are creating.  We may
+            // The caller query has more dependencies than the node we are creating. We may
             // encounter a case where this created node is marked as green, but the caller query is
-            // subsequently marked as red or recomputed.  In this case, we will end up feeding a
+            // subsequently marked as red or recomputed. In this case, we will end up feeding a
             // value to an existing node.
             //
             // For sanity, we still check that the loaded stable hash and the new one match.
@@ -980,7 +980,7 @@ struct EdgeIndex {}
 /// graph: they are only added.
 ///
 /// The nodes in it are identified by a `DepNodeIndex`. We avoid keeping the nodes
-/// in memory.  This is important, because these graph structures are some of the
+/// in memory. This is important, because these graph structures are some of the
 /// largest in the compiler.
 ///
 /// For this reason, we avoid storing `DepNode`s more than once as map
index dfc1344f85c70cabbeb86f452cbd8abc704203dc..a81595b2420c041e9c8e535483c8fc3f5f601dfd 100644 (file)
@@ -1,14 +1,14 @@
 //! The data that we will serialize and deserialize.
 //!
 //! The dep-graph is serialized as a sequence of NodeInfo, with the dependencies
-//! specified inline.  The total number of nodes and edges are stored as the last
+//! specified inline. The total number of nodes and edges are stored as the last
 //! 16 bytes of the file, so we can find them easily at decoding time.
 //!
 //! The serialisation is performed on-demand when each node is emitted. Using this
 //! scheme, we do not need to keep the current graph in memory.
 //!
 //! The deserialization is performed manually, in order to convert from the stored
-//! sequence of NodeInfos to the different arrays in SerializedDepGraph.  Since the
+//! sequence of NodeInfos to the different arrays in SerializedDepGraph. Since the
 //! node and edge count are stored at the end of the file, all the arrays can be
 //! pre-allocated with the right length.
 
index f65846fc77f6e5114bfd384ce37c013c61e10e62..77d0d0314fc17de7a36de449436e484118bec350 100644 (file)
@@ -116,7 +116,7 @@ fn complete(&self, key: K, value: V, index: DepNodeIndex) -> Self::Stored {
         let mut lock = self.cache.get_shard_by_value(&key).lock();
         #[cfg(not(parallel_compiler))]
         let mut lock = self.cache.lock();
-        // We may be overwriting another value.  This is all right, since the dep-graph
+        // We may be overwriting another value. This is all right, since the dep-graph
         // will check that the fingerprint matches.
         lock.insert(key, (value.clone(), index));
         value
@@ -203,7 +203,7 @@ fn complete(&self, key: K, value: V, index: DepNodeIndex) -> Self::Stored {
         let mut lock = self.cache.get_shard_by_value(&key).lock();
         #[cfg(not(parallel_compiler))]
         let mut lock = self.cache.lock();
-        // We may be overwriting another value.  This is all right, since the dep-graph
+        // We may be overwriting another value. This is all right, since the dep-graph
         // will check that the fingerprint matches.
         lock.insert(key, value);
         &value.0
index 32fb5e18276ab86fe721f533c56d88871cb2e44c..eae4c9992eb08d4a6c31118b0fb73abf8d5ce2ea 100644 (file)
@@ -28,9 +28,9 @@
 use crate::Resolver;
 
 use rustc_ast as ast;
-use rustc_ast::node_id::NodeMap;
 use rustc_ast::visit::{self, Visitor};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{pluralize, MultiSpan};
 use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS};
 use rustc_session::lint::BuiltinLintDiagnostics;
@@ -40,7 +40,7 @@ struct UnusedImport<'a> {
     use_tree: &'a ast::UseTree,
     use_tree_id: ast::NodeId,
     item_span: Span,
-    unused: FxHashSet<ast::NodeId>,
+    unused: UnordSet<ast::NodeId>,
 }
 
 impl<'a> UnusedImport<'a> {
@@ -52,7 +52,7 @@ fn add(&mut self, id: ast::NodeId) {
 struct UnusedImportCheckVisitor<'a, 'b> {
     r: &'a mut Resolver<'b>,
     /// All the (so far) unused imports, grouped path list
-    unused_imports: NodeMap<UnusedImport<'a>>,
+    unused_imports: FxIndexMap<ast::NodeId, UnusedImport<'a>>,
     base_use_tree: Option<&'a ast::UseTree>,
     base_id: ast::NodeId,
     item_span: Span,
@@ -89,7 +89,7 @@ fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport<'a> {
             use_tree,
             use_tree_id,
             item_span,
-            unused: FxHashSet::default(),
+            unused: Default::default(),
         })
     }
 }
index fb2aebbd18a3d8508e5d06fc0eeba2e58f479f7a..36608615255586a45f76d16394429b231285e7ef 100644 (file)
@@ -5,10 +5,10 @@
 use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
 use rustc_errors::{
     pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
 };
+use rustc_errors::{struct_span_err, SuggestionStyle};
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
@@ -1033,7 +1033,7 @@ fn early_lookup_typo_candidate(
                     let root_module = this.resolve_crate_root(root_ident);
                     this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
                 }
-                Scope::Module(module) => {
+                Scope::Module(module, _) => {
                     this.add_module_candidates(module, &mut suggestions, filter_fn, None);
                 }
                 Scope::MacroUsePrelude => {
@@ -2125,9 +2125,15 @@ pub(crate) fn check_for_module_export_macro(
 
                 let source_map = self.r.session.source_map();
 
+                // Make sure this is actually crate-relative.
+                let is_definitely_crate = import
+                    .module_path
+                    .first()
+                    .map_or(false, |f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
+
                 // Add the import to the start, with a `{` if required.
                 let start_point = source_map.start_point(after_crate_name);
-                if let Ok(start_snippet) = source_map.span_to_snippet(start_point) {
+                if is_definitely_crate && let Ok(start_snippet) = source_map.span_to_snippet(start_point) {
                     corrections.push((
                         start_point,
                         if has_nested {
@@ -2139,11 +2145,17 @@ pub(crate) fn check_for_module_export_macro(
                             format!("{{{}, {}", import_snippet, start_snippet)
                         },
                     ));
-                }
 
-                // Add a `};` to the end if nested, matching the `{` added at the start.
-                if !has_nested {
-                    corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
+                    // Add a `};` to the end if nested, matching the `{` added at the start.
+                    if !has_nested {
+                        corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
+                    }
+                } else {
+                    // If the root import is module-relative, add the import separately
+                    corrections.push((
+                        import.use_span.shrink_to_lo(),
+                        format!("use {module_name}::{import_snippet};\n"),
+                    ));
                 }
             }
 
@@ -2418,7 +2430,7 @@ fn show_candidates(
         }
 
         if let Some(span) = use_placement_span {
-            let add_use = match mode {
+            let (add_use, trailing) = match mode {
                 DiagnosticMode::Pattern => {
                     err.span_suggestions(
                         span,
@@ -2428,21 +2440,23 @@ fn show_candidates(
                     );
                     return;
                 }
-                DiagnosticMode::Import => "",
-                DiagnosticMode::Normal => "use ",
+                DiagnosticMode::Import => ("", ""),
+                DiagnosticMode::Normal => ("use ", ";\n"),
             };
             for candidate in &mut accessible_path_strings {
                 // produce an additional newline to separate the new use statement
                 // from the directly following item.
-                let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" };
-                candidate.0 = format!("{add_use}{}{append};\n{additional_newline}", &candidate.0);
+                let additional_newline = if let FoundUse::No = found_use && let DiagnosticMode::Normal = mode { "\n" } else { "" };
+                candidate.0 =
+                    format!("{add_use}{}{append}{trailing}{additional_newline}", &candidate.0);
             }
 
-            err.span_suggestions(
+            err.span_suggestions_with_style(
                 span,
                 &msg,
                 accessible_path_strings.into_iter().map(|a| a.0),
                 Applicability::MaybeIncorrect,
+                SuggestionStyle::ShowAlways,
             );
             if let [first, .., last] = &path[..] {
                 let sp = first.ident.span.until(last.ident.span);
@@ -2463,7 +2477,7 @@ fn show_candidates(
                 msg.push_str(&candidate.0);
             }
 
-            err.note(&msg);
+            err.help(&msg);
         }
     } else if !matches!(mode, DiagnosticMode::Import) {
         assert!(!inaccessible_path_strings.is_empty());
index e41fe325b811cb42cf118565782a00e1f75df0eb..a84652a315dc2d5ef95b197acee8025c6e088ebb 100644 (file)
@@ -1,9 +1,11 @@
-use rustc_ast as ast;
+use rustc_ast::{self as ast, NodeId};
 use rustc_feature::is_builtin_attr_name;
 use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS};
 use rustc_hir::PrimTy;
 use rustc_middle::bug;
 use rustc_middle::ty;
+use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
+use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
@@ -99,7 +101,7 @@ pub(crate) fn visit_scopes<T>(
         };
         let mut scope = match ns {
             _ if is_absolute_path => Scope::CrateRoot,
-            TypeNS | ValueNS => Scope::Module(module),
+            TypeNS | ValueNS => Scope::Module(module, None),
             MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
         };
         let mut ctxt = ctxt.normalize_to_macros_2_0();
@@ -163,7 +165,7 @@ pub(crate) fn visit_scopes<T>(
                     MacroRulesScope::Invocation(invoc_id) => {
                         Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules)
                     }
-                    MacroRulesScope::Empty => Scope::Module(module),
+                    MacroRulesScope::Empty => Scope::Module(module, None),
                 },
                 Scope::CrateRoot => match ns {
                     TypeNS => {
@@ -172,10 +174,16 @@ pub(crate) fn visit_scopes<T>(
                     }
                     ValueNS | MacroNS => break,
                 },
-                Scope::Module(module) => {
+                Scope::Module(module, prev_lint_id) => {
                     use_prelude = !module.no_implicit_prelude;
-                    match self.hygienic_lexical_parent(module, &mut ctxt) {
-                        Some(parent_module) => Scope::Module(parent_module),
+                    let derive_fallback_lint_id = match scope_set {
+                        ScopeSet::Late(.., lint_id) => lint_id,
+                        _ => None,
+                    };
+                    match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) {
+                        Some((parent_module, lint_id)) => {
+                            Scope::Module(parent_module, lint_id.or(prev_lint_id))
+                        }
                         None => {
                             ctxt.adjust(ExpnId::root());
                             match ns {
@@ -207,13 +215,45 @@ fn hygienic_lexical_parent(
         &mut self,
         module: Module<'a>,
         ctxt: &mut SyntaxContext,
-    ) -> Option<Module<'a>> {
+        derive_fallback_lint_id: Option<NodeId>,
+    ) -> Option<(Module<'a>, Option<NodeId>)> {
         if !module.expansion.outer_expn_is_descendant_of(*ctxt) {
-            return Some(self.expn_def_scope(ctxt.remove_mark()));
+            return Some((self.expn_def_scope(ctxt.remove_mark()), None));
         }
 
         if let ModuleKind::Block = module.kind {
-            return Some(module.parent.unwrap().nearest_item_scope());
+            return Some((module.parent.unwrap().nearest_item_scope(), None));
+        }
+
+        // We need to support the next case under a deprecation warning
+        // ```
+        // struct MyStruct;
+        // ---- begin: this comes from a proc macro derive
+        // mod implementation_details {
+        //     // Note that `MyStruct` is not in scope here.
+        //     impl SomeTrait for MyStruct { ... }
+        // }
+        // ---- end
+        // ```
+        // So we have to fall back to the module's parent during lexical resolution in this case.
+        if derive_fallback_lint_id.is_some() {
+            if let Some(parent) = module.parent {
+                // Inner module is inside the macro, parent module is outside of the macro.
+                if module.expansion != parent.expansion
+                    && module.expansion.is_descendant_of(parent.expansion)
+                {
+                    // The macro is a proc macro derive
+                    if let Some(def_id) = module.expansion.expn_data().macro_def_id {
+                        let ext = self.get_macro_by_def_id(def_id).ext;
+                        if ext.builtin_name.is_none()
+                            && ext.macro_kind() == MacroKind::Derive
+                            && parent.expansion.outer_expn_is_descendant_of(*ctxt)
+                        {
+                            return Some((parent, derive_fallback_lint_id));
+                        }
+                    }
+                }
+            }
         }
 
         None
@@ -470,7 +510,7 @@ struct Flags: u8 {
                             Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
                         }
                     }
-                    Scope::Module(module) => {
+                    Scope::Module(module, derive_fallback_lint_id) => {
                         let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
                         let binding = this.resolve_ident_in_module_unadjusted_ext(
                             ModuleOrUniformRoot::Module(module),
@@ -483,6 +523,21 @@ struct Flags: u8 {
                         );
                         match binding {
                             Ok(binding) => {
+                                if let Some(lint_id) = derive_fallback_lint_id {
+                                    this.lint_buffer.buffer_lint_with_diagnostic(
+                                        PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
+                                        lint_id,
+                                        orig_ident.span,
+                                        &format!(
+                                            "cannot find {} `{}` in this scope",
+                                            ns.descr(),
+                                            ident
+                                        ),
+                                        BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(
+                                            orig_ident.span,
+                                        ),
+                                    );
+                                }
                                 let misc_flags = if ptr::eq(module, this.graph_root) {
                                     Flags::MISC_SUGGEST_CRATE
                                 } else if module.is_normal() {
index ca43762aa214ec63c846c738a8a8aabe90d86e64..83932c089b311afba738f9e3fb9ff652befe1079 100644 (file)
@@ -668,7 +668,7 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
                     && let Some(partial_res) = self.r.partial_res_map.get(&ty.id)
                     && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
                 {
-                    // This path is actually a bare trait object.  In case of a bare `Fn`-trait
+                    // This path is actually a bare trait object. In case of a bare `Fn`-trait
                     // object with anonymous lifetimes, we need this rib to correctly place the
                     // synthetic lifetimes.
                     let span = ty.span.shrink_to_lo().to(path.span.shrink_to_lo());
@@ -1046,7 +1046,7 @@ fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) {
                     // Probe the lifetime ribs to know how to behave.
                     for rib in self.lifetime_ribs.iter().rev() {
                         match rib.kind {
-                            // We are inside a `PolyTraitRef`.  The lifetimes are
+                            // We are inside a `PolyTraitRef`. The lifetimes are
                             // to be intoduced in that (maybe implicit) `for<>` binder.
                             LifetimeRibKind::Generics {
                                 binder,
@@ -1069,7 +1069,7 @@ fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) {
                                 );
                                 break;
                             }
-                            // We have nowhere to introduce generics.  Code is malformed,
+                            // We have nowhere to introduce generics. Code is malformed,
                             // so use regular lifetime resolution to avoid spurious errors.
                             LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => {
                                 visit::walk_generic_args(self, args);
@@ -1775,7 +1775,7 @@ fn resolve_elided_lifetimes_in_path(
                         break;
                     }
                     // `LifetimeRes::Error`, which would usually be used in the case of
-                    // `ReportError`, is unsuitable here, as we don't emit an error yet.  Instead,
+                    // `ReportError`, is unsuitable here, as we don't emit an error yet. Instead,
                     // we simply resolve to an implicit lifetime, which will be checked later, at
                     // which point a suitable error will be emitted.
                     LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
@@ -3373,7 +3373,7 @@ fn smart_resolve_path_fragment(
                         sugg.to_string(),
                         Applicability::MaybeIncorrect,
                     ))
-                } else if res.is_none() {
+                } else if res.is_none() && matches!(source, PathSource::Type) {
                     this.report_missing_type_error(path)
                 } else {
                     None
@@ -3647,7 +3647,7 @@ fn resolve_qpath(
         if let Some(qself) = qself {
             if qself.position == 0 {
                 // This is a case like `<T>::B`, where there is no
-                // trait to resolve.  In that case, we leave the `B`
+                // trait to resolve. In that case, we leave the `B`
                 // segment to be resolved by type-check.
                 return Ok(Some(PartialRes::with_unresolved_segments(
                     Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()),
@@ -3658,7 +3658,7 @@ fn resolve_qpath(
             // Make sure `A::B` in `<T as A::B>::C` is a trait item.
             //
             // Currently, `path` names the full item (`A::B::C`, in
-            // our example).  so we extract the prefix of that that is
+            // our example). so we extract the prefix of that that is
             // the trait (the slice upto and including
             // `qself.position`). And then we recursively resolve that,
             // but with `qself` set to `None`.
index d92b046d0b9f226fe3bb0f3111a09658acef8303..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 {
@@ -2188,15 +2195,31 @@ pub(crate) fn maybe_report_lifetime_uses(
             let deletion_span = || {
                 if params.len() == 1 {
                     // if sole lifetime, remove the entire `<>` brackets
-                    generics_span
+                    Some(generics_span)
                 } else if param_index == 0 {
                     // if removing within `<>` brackets, we also want to
                     // delete a leading or trailing comma as appropriate
-                    param.span().to(params[param_index + 1].span().shrink_to_lo())
+                    match (
+                        param.span().find_ancestor_inside(generics_span),
+                        params[param_index + 1].span().find_ancestor_inside(generics_span),
+                    ) {
+                        (Some(param_span), Some(next_param_span)) => {
+                            Some(param_span.to(next_param_span.shrink_to_lo()))
+                        }
+                        _ => None,
+                    }
                 } else {
                     // if removing within `<>` brackets, we also want to
                     // delete a leading or trailing comma as appropriate
-                    params[param_index - 1].span().shrink_to_hi().to(param.span())
+                    match (
+                        param.span().find_ancestor_inside(generics_span),
+                        params[param_index - 1].span().find_ancestor_inside(generics_span),
+                    ) {
+                        (Some(param_span), Some(prev_param_span)) => {
+                            Some(prev_param_span.shrink_to_hi().to(param_span))
+                        }
+                        _ => None,
+                    }
                 }
             };
             match use_set {
index f950e4a9bee65282e8ae37a9358f1d408191e00d..1b181b714005bd7177d2a1cd1ce29358301d6020 100644 (file)
@@ -105,7 +105,9 @@ enum Scope<'a> {
     DeriveHelpersCompat,
     MacroRules(MacroRulesScopeRef<'a>),
     CrateRoot,
-    Module(Module<'a>),
+    // The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
+    // lint if it should be reported.
+    Module(Module<'a>, Option<NodeId>),
     MacroUsePrelude,
     BuiltinAttrs,
     ExternPrelude,
@@ -1591,7 +1593,7 @@ pub fn traits_in_scope(
 
         self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| {
             match scope {
-                Scope::Module(module) => {
+                Scope::Module(module, _) => {
                     this.traits_in_module(module, assoc_item, &mut found_traits);
                 }
                 Scope::StdLibPrelude => {
index 9ae07cb005bd41b0db70ee91e528cf9db13bd741..3982111e38e08307f6aaacebe270a3c947f2cd78 100644 (file)
@@ -112,9 +112,7 @@ fn lookup_def_id(&self, ref_id: hir::HirId) -> Option<DefId> {
     }
 
     pub fn dump_crate_info(&mut self, name: Symbol) {
-        let source_file = self.tcx.sess.local_crate_source_file.as_ref();
-        let crate_root = source_file.map(|source_file| {
-            let source_file = Path::new(source_file);
+        let crate_root = self.tcx.sess.local_crate_source_file().map(|source_file| {
             match source_file.file_name() {
                 Some(_) => source_file.parent().unwrap().display(),
                 None => source_file.display(),
@@ -157,10 +155,14 @@ pub fn dump_compilation_options(&mut self, input: &Input, crate_name: Symbol) {
                 .enumerate()
                 .filter(|(i, _)| !remap_arg_indices.contains(i))
                 .map(|(_, arg)| match input {
-                    Input::File(ref path) if path == Path::new(&arg) => {
-                        let mapped = &self.tcx.sess.local_crate_source_file;
-                        mapped.as_ref().unwrap().to_string_lossy().into()
-                    }
+                    Input::File(ref path) if path == Path::new(&arg) => self
+                        .tcx
+                        .sess
+                        .local_crate_source_file()
+                        .as_ref()
+                        .unwrap()
+                        .to_string_lossy()
+                        .into(),
                     _ => arg,
                 });
 
@@ -209,7 +211,7 @@ fn process_formals(&mut self, formals: &'tcx [hir::Param<'tcx>], qualname: &str)
                     None => continue,
                 };
                 if !self.span.filter_generated(ident.span) {
-                    let id = id_from_hir_id(hir_id, &self.save_ctxt);
+                    let id = id_from_hir_id(hir_id);
                     let span = self.span_from_span(ident.span);
 
                     self.dumper.dump_def(
@@ -238,17 +240,17 @@ fn process_method(
         &mut self,
         sig: &'tcx hir::FnSig<'tcx>,
         body: Option<hir::BodyId>,
-        def_id: LocalDefId,
+        owner_id: hir::OwnerId,
         ident: Ident,
         generics: &'tcx hir::Generics<'tcx>,
         span: Span,
     ) {
-        debug!("process_method: {:?}:{}", def_id, ident);
+        debug!("process_method: {:?}:{}", owner_id, ident);
 
         let map = self.tcx.hir();
-        let hir_id = map.local_def_id_to_hir_id(def_id);
-        self.nest_typeck_results(def_id, |v| {
-            if let Some(mut method_data) = v.save_ctxt.get_method_data(hir_id, ident, span) {
+        let hir_id: hir::HirId = owner_id.into();
+        self.nest_typeck_results(owner_id.def_id, |v| {
+            if let Some(mut method_data) = v.save_ctxt.get_method_data(owner_id, ident, span) {
                 if let Some(body) = body {
                     v.process_formals(map.body(body).params, &method_data.qualname);
                 }
@@ -256,9 +258,10 @@ fn process_method(
 
                 method_data.value =
                     fn_to_string(sig.decl, sig.header, Some(ident.name), generics, &[], None);
-                method_data.sig = sig::method_signature(hir_id, ident, generics, sig, &v.save_ctxt);
+                method_data.sig =
+                    sig::method_signature(owner_id, ident, generics, sig, &v.save_ctxt);
 
-                v.dumper.dump_def(&access_from!(v.save_ctxt, def_id), method_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, owner_id.def_id), method_data);
             }
 
             // walk arg and return types
@@ -280,14 +283,11 @@ fn process_method(
     fn process_struct_field_def(
         &mut self,
         field: &'tcx hir::FieldDef<'tcx>,
-        parent_id: hir::HirId,
+        parent_id: LocalDefId,
     ) {
         let field_data = self.save_ctxt.get_field_data(field, parent_id);
         if let Some(field_data) = field_data {
-            self.dumper.dump_def(
-                &access_from!(self.save_ctxt, self.tcx.hir().local_def_id(field.hir_id)),
-                field_data,
-            );
+            self.dumper.dump_def(&access_from!(self.save_ctxt, field.def_id), field_data);
         }
     }
 
@@ -307,7 +307,7 @@ fn process_generic_params(
                     // Append $id to name to make sure each one is unique.
                     let qualname = format!("{}::{}${}", prefix, name, id);
                     if !self.span.filter_generated(param_ss) {
-                        let id = id_from_hir_id(param.hir_id, &self.save_ctxt);
+                        let id = id_from_def_id(param.def_id.to_def_id());
                         let span = self.span_from_span(param_ss);
 
                         self.dumper.dump_def(
@@ -385,25 +385,24 @@ fn process_static_or_const_item(
 
     fn process_assoc_const(
         &mut self,
-        def_id: LocalDefId,
+        owner_id: hir::OwnerId,
         ident: Ident,
         typ: &'tcx hir::Ty<'tcx>,
         expr: Option<&'tcx hir::Expr<'tcx>>,
         parent_id: DefId,
         attrs: &'tcx [ast::Attribute],
     ) {
-        let qualname = format!("::{}", self.tcx.def_path_str(def_id.to_def_id()));
+        let qualname = format!("::{}", self.tcx.def_path_str(owner_id.to_def_id()));
 
         if !self.span.filter_generated(ident.span) {
-            let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-            let sig = sig::assoc_const_signature(hir_id, ident.name, typ, expr, &self.save_ctxt);
+            let sig = sig::assoc_const_signature(owner_id, ident.name, typ, expr, &self.save_ctxt);
             let span = self.span_from_span(ident.span);
 
             self.dumper.dump_def(
-                &access_from!(self.save_ctxt, def_id),
+                &access_from!(self.save_ctxt, owner_id.def_id),
                 Def {
                     kind: DefKind::Const,
-                    id: id_from_hir_id(hir_id, &self.save_ctxt),
+                    id: id_from_def_id(owner_id.to_def_id()),
                     span,
                     name: ident.name.to_string(),
                     qualname,
@@ -419,7 +418,7 @@ fn process_assoc_const(
         }
 
         // walk type and init value
-        self.nest_typeck_results(def_id, |v| {
+        self.nest_typeck_results(owner_id.def_id, |v| {
             v.visit_ty(typ);
             if let Some(expr) = expr {
                 v.visit_expr(expr);
@@ -454,8 +453,7 @@ fn process_struct(
                         if include_priv_fields {
                             return Some(f.ident.to_string());
                         }
-                        let def_id = self.save_ctxt.tcx.hir().local_def_id(f.hir_id);
-                        if self.save_ctxt.tcx.visibility(def_id).is_public() {
+                        if self.save_ctxt.tcx.visibility(f.def_id).is_public() {
                             Some(f.ident.to_string())
                         } else {
                             None
@@ -464,7 +462,7 @@ fn process_struct(
                     .collect::<Vec<_>>()
                     .join(", ");
                 let value = format!("{} {{ {} }}", name, fields_str);
-                (value, fields.iter().map(|f| id_from_hir_id(f.hir_id, &self.save_ctxt)).collect())
+                (value, fields.iter().map(|f| id_from_def_id(f.def_id.to_def_id())).collect())
             }
             _ => (String::new(), vec![]),
         };
@@ -493,7 +491,7 @@ fn process_struct(
 
         self.nest_typeck_results(item.owner_id.def_id, |v| {
             for field in def.fields() {
-                v.process_struct_field_def(field, item.hir_id());
+                v.process_struct_field_def(field, item.owner_id.def_id);
                 v.visit_ty(&field.ty);
             }
 
@@ -527,7 +525,7 @@ fn process_enum(
                     let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
                     if !self.span.filter_generated(name_span) {
                         let span = self.span_from_span(name_span);
-                        let id = id_from_hir_id(variant.hir_id, &self.save_ctxt);
+                        let id = id_from_def_id(variant.def_id.to_def_id());
                         let parent = Some(id_from_def_id(item.owner_id.to_def_id()));
                         let attrs = self.tcx.hir().attrs(variant.hir_id);
 
@@ -565,7 +563,7 @@ fn process_enum(
                     }
                     if !self.span.filter_generated(name_span) {
                         let span = self.span_from_span(name_span);
-                        let id = id_from_hir_id(variant.hir_id, &self.save_ctxt);
+                        let id = id_from_def_id(variant.def_id.to_def_id());
                         let parent = Some(id_from_def_id(item.owner_id.to_def_id()));
                         let attrs = self.tcx.hir().attrs(variant.hir_id);
 
@@ -591,7 +589,7 @@ fn process_enum(
             }
 
             for field in variant.data.fields() {
-                self.process_struct_field_def(field, variant.hir_id);
+                self.process_struct_field_def(field, variant.def_id);
                 self.visit_ty(field.ty);
             }
         }
@@ -881,7 +879,7 @@ fn process_var_decl(&mut self, pat: &'tcx hir::Pat<'tcx>) {
                     // Rust uses the id of the pattern for var lookups, so we'll use it too.
                     if !self.span.filter_generated(ident.span) {
                         let qualname = format!("{}${}", ident, hir_id);
-                        let id = id_from_hir_id(hir_id, &self.save_ctxt);
+                        let id = id_from_hir_id(hir_id);
                         let span = self.span_from_span(ident.span);
 
                         self.dumper.dump_def(
@@ -981,7 +979,7 @@ fn process_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>, trait_i
                 let body = body.map(|b| self.tcx.hir().body(b).value);
                 let attrs = self.tcx.hir().attrs(trait_item.hir_id());
                 self.process_assoc_const(
-                    trait_item.owner_id.def_id,
+                    trait_item.owner_id,
                     trait_item.ident,
                     &ty,
                     body,
@@ -995,7 +993,7 @@ fn process_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>, trait_i
                 self.process_method(
                     sig,
                     body,
-                    trait_item.owner_id.def_id,
+                    trait_item.owner_id,
                     trait_item.ident,
                     &trait_item.generics,
                     trait_item.span,
@@ -1026,7 +1024,7 @@ fn process_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>, trait_i
                             decl_id: None,
                             docs: self.save_ctxt.docs_for_attrs(attrs),
                             sig: sig::assoc_type_signature(
-                                trait_item.hir_id(),
+                                trait_item.owner_id,
                                 trait_item.ident,
                                 Some(bounds),
                                 default_ty.as_deref(),
@@ -1051,7 +1049,7 @@ fn process_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>, impl_id: D
                 let body = self.tcx.hir().body(body);
                 let attrs = self.tcx.hir().attrs(impl_item.hir_id());
                 self.process_assoc_const(
-                    impl_item.owner_id.def_id,
+                    impl_item.owner_id,
                     impl_item.ident,
                     &ty,
                     Some(&body.value),
@@ -1063,7 +1061,7 @@ fn process_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>, impl_id: D
                 self.process_method(
                     sig,
                     Some(body),
-                    impl_item.owner_id.def_id,
+                    impl_item.owner_id,
                     impl_item.ident,
                     &impl_item.generics,
                     impl_item.span,
@@ -1079,18 +1077,16 @@ fn process_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>, impl_id: D
     }
 
     pub(crate) fn process_crate(&mut self) {
-        let id = hir::CRATE_HIR_ID;
-        let qualname =
-            format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(id).to_def_id()));
+        let qualname = format!("::{}", self.tcx.def_path_str(CRATE_DEF_ID.to_def_id()));
 
         let sm = self.tcx.sess.source_map();
         let krate_mod = self.tcx.hir().root_module();
         let filename = sm.span_to_filename(krate_mod.spans.inner_span);
-        let data_id = id_from_hir_id(id, &self.save_ctxt);
+        let data_id = id_from_def_id(CRATE_DEF_ID.to_def_id());
         let children =
             krate_mod.item_ids.iter().map(|i| id_from_def_id(i.owner_id.to_def_id())).collect();
         let span = self.span_from_span(krate_mod.spans.inner_span);
-        let attrs = self.tcx.hir().attrs(id);
+        let attrs = self.tcx.hir().attrs(hir::CRATE_HIR_ID);
 
         self.dumper.dump_def(
             &Access { public: true, reachable: true },
@@ -1317,7 +1313,7 @@ fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
                     // output the inferred type here? :shrug:
                     hir::ArrayLen::Infer(..) => {}
                     hir::ArrayLen::Body(anon_const) => self
-                        .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                        .nest_typeck_results(anon_const.def_id, |v| {
                             v.visit_expr(&map.body(anon_const.body).value)
                         }),
                 }
@@ -1359,7 +1355,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
                     }
                 }
             }
-            hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, .. }) => {
+            hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, def_id, .. }) => {
                 let id = format!("${}", ex.hir_id);
 
                 // walk arg and return types
@@ -1373,7 +1369,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
 
                 // walk the body
                 let map = self.tcx.hir();
-                self.nest_typeck_results(self.tcx.hir().local_def_id(ex.hir_id), |v| {
+                self.nest_typeck_results(def_id, |v| {
                     let body = map.body(body);
                     v.process_formals(body.params, &id);
                     v.visit_expr(&body.value)
@@ -1387,7 +1383,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
                     // output the inferred type here? :shrug:
                     hir::ArrayLen::Infer(..) => {}
                     hir::ArrayLen::Body(anon_const) => self
-                        .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                        .nest_typeck_results(anon_const.def_id, |v| {
                             v.visit_expr(&map.body(anon_const.body).value)
                         }),
                 }
index a8d82de02b7548836d5b8e3a7e70ae07caab06a2..a9a92cc4f62ed9102a3039f58f01657f60eaef8d 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_ast_pretty::pprust::attribute_to_string;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind as HirDefKind, Res};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::Node;
 use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string};
@@ -318,7 +318,7 @@ pub fn get_item_data(&self, item: &hir::Item<'_>) -> Option<Data> {
                     qualname,
                     value,
                     parent: None,
-                    children: def.variants.iter().map(|v| id_from_hir_id(v.hir_id, self)).collect(),
+                    children: def.variants.iter().map(|v| id_from_def_id(v.def_id.to_def_id())).collect(),
                     decl_id: None,
                     docs: self.docs_for_attrs(attrs),
                     sig: sig::item_signature(item, self),
@@ -379,12 +379,11 @@ pub fn get_item_data(&self, item: &hir::Item<'_>) -> Option<Data> {
         }
     }
 
-    pub fn get_field_data(&self, field: &hir::FieldDef<'_>, scope: hir::HirId) -> Option<Def> {
+    pub fn get_field_data(&self, field: &hir::FieldDef<'_>, scope: LocalDefId) -> Option<Def> {
         let name = field.ident.to_string();
-        let scope_def_id = self.tcx.hir().local_def_id(scope).to_def_id();
-        let qualname = format!("::{}::{}", self.tcx.def_path_str(scope_def_id), field.ident);
+        let qualname = format!("::{}::{}", self.tcx.def_path_str(scope.to_def_id()), field.ident);
         filter!(self.span_utils, field.ident.span);
-        let field_def_id = self.tcx.hir().local_def_id(field.hir_id).to_def_id();
+        let field_def_id = field.def_id.to_def_id();
         let typ = self.tcx.type_of(field_def_id).to_string();
 
         let id = id_from_def_id(field_def_id);
@@ -398,7 +397,7 @@ pub fn get_field_data(&self, field: &hir::FieldDef<'_>, scope: hir::HirId) -> Op
             name,
             qualname,
             value: typ,
-            parent: Some(id_from_def_id(scope_def_id)),
+            parent: Some(id_from_def_id(scope.to_def_id())),
             children: vec![],
             decl_id: None,
             docs: self.docs_for_attrs(attrs),
@@ -409,12 +408,11 @@ pub fn get_field_data(&self, field: &hir::FieldDef<'_>, scope: hir::HirId) -> Op
 
     // FIXME would be nice to take a MethodItem here, but the ast provides both
     // trait and impl flavours, so the caller must do the disassembly.
-    pub fn get_method_data(&self, hir_id: hir::HirId, ident: Ident, span: Span) -> Option<Def> {
+    pub fn get_method_data(&self, owner_id: hir::OwnerId, ident: Ident, span: Span) -> Option<Def> {
         // The qualname for a method is the trait name or name of the struct in an impl in
         // which the method is declared in, followed by the method's name.
-        let def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
         let (qualname, parent_scope, decl_id, docs, attributes) =
-            match self.tcx.impl_of_method(def_id) {
+            match self.tcx.impl_of_method(owner_id.to_def_id()) {
                 Some(impl_id) => match self.tcx.hir().get_if_local(impl_id) {
                     Some(Node::Item(item)) => match item.kind {
                         hir::ItemKind::Impl(hir::Impl { ref self_ty, .. }) => {
@@ -427,8 +425,8 @@ pub fn get_method_data(&self, hir_id: hir::HirId, ident: Ident, span: Span) -> O
                             let trait_id = self.tcx.trait_id_of_impl(impl_id);
                             let mut docs = String::new();
                             let mut attrs = vec![];
-                            if let Some(Node::ImplItem(_)) = hir.find(hir_id) {
-                                attrs = self.tcx.hir().attrs(hir_id).to_vec();
+                            if let Some(Node::ImplItem(_)) = hir.find(owner_id.into()) {
+                                attrs = self.tcx.hir().attrs(owner_id.into()).to_vec();
                                 docs = self.docs_for_attrs(&attrs);
                             }
 
@@ -452,29 +450,29 @@ pub fn get_method_data(&self, hir_id: hir::HirId, ident: Ident, span: Span) -> O
                         _ => {
                             span_bug!(
                                 span,
-                                "Container {:?} for method {} not an impl?",
+                                "Container {:?} for method {:?} not an impl?",
                                 impl_id,
-                                hir_id
+                                owner_id,
                             );
                         }
                     },
                     r => {
                         span_bug!(
                             span,
-                            "Container {:?} for method {} is not a node item {:?}",
+                            "Container {:?} for method {:?} is not a node item {:?}",
                             impl_id,
-                            hir_id,
+                            owner_id,
                             r
                         );
                     }
                 },
-                None => match self.tcx.trait_of_item(def_id) {
+                None => match self.tcx.trait_of_item(owner_id.to_def_id()) {
                     Some(def_id) => {
                         let mut docs = String::new();
                         let mut attrs = vec![];
 
-                        if let Some(Node::TraitItem(_)) = self.tcx.hir().find(hir_id) {
-                            attrs = self.tcx.hir().attrs(hir_id).to_vec();
+                        if let Some(Node::TraitItem(_)) = self.tcx.hir().find(owner_id.into()) {
+                            attrs = self.tcx.hir().attrs(owner_id.into()).to_vec();
                             docs = self.docs_for_attrs(&attrs);
                         }
 
@@ -487,7 +485,7 @@ pub fn get_method_data(&self, hir_id: hir::HirId, ident: Ident, span: Span) -> O
                         )
                     }
                     None => {
-                        debug!("could not find container for method {} at {:?}", hir_id, span);
+                        debug!("could not find container for method {:?} at {:?}", owner_id, span);
                         // This is not necessarily a bug, if there was a compilation error,
                         // the typeck results we need might not exist.
                         return None;
@@ -501,7 +499,7 @@ pub fn get_method_data(&self, hir_id: hir::HirId, ident: Ident, span: Span) -> O
 
         Some(Def {
             kind: DefKind::Method,
-            id: id_from_def_id(def_id),
+            id: id_from_def_id(owner_id.to_def_id()),
             span: self.span_from_span(ident.span),
             name: ident.name.to_string(),
             qualname,
@@ -669,7 +667,7 @@ fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
 
         match res {
             Res::Local(id) => {
-                Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_hir_id(id, self) })
+                Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_hir_id(id) })
             }
             Res::Def(HirDefKind::Trait, def_id) if fn_type(path_seg) => {
                 Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(def_id) })
@@ -1033,18 +1031,15 @@ fn id_from_def_id(id: DefId) -> rls_data::Id {
     rls_data::Id { krate: id.krate.as_u32(), index: id.index.as_u32() }
 }
 
-fn id_from_hir_id(id: hir::HirId, scx: &SaveContext<'_>) -> rls_data::Id {
-    let def_id = scx.tcx.hir().opt_local_def_id(id);
-    def_id.map(|id| id_from_def_id(id.to_def_id())).unwrap_or_else(|| {
-        // Create a *fake* `DefId` out of a `HirId` by combining the owner
-        // `local_def_index` and the `local_id`.
-        // This will work unless you have *billions* of definitions in a single
-        // crate (very unlikely to actually happen).
-        rls_data::Id {
-            krate: LOCAL_CRATE.as_u32(),
-            index: id.owner.def_id.local_def_index.as_u32() | id.local_id.as_u32().reverse_bits(),
-        }
-    })
+fn id_from_hir_id(id: hir::HirId) -> rls_data::Id {
+    // Create a *fake* `DefId` out of a `HirId` by combining the owner
+    // `local_def_index` and the `local_id`.
+    // This will work unless you have *billions* of definitions in a single
+    // crate (very unlikely to actually happen).
+    rls_data::Id {
+        krate: LOCAL_CRATE.as_u32(),
+        index: id.owner.def_id.local_def_index.as_u32() | id.local_id.as_u32().reverse_bits(),
+    }
 }
 
 fn null_id() -> rls_data::Id {
index 5a1bcb8fdc87be9a82047dbed9040ee4e3c17afd..979305547c14b23afe616ee78f6d9d88993aed5a 100644 (file)
@@ -25,7 +25,7 @@
 //
 // FIXME where clauses need implementing, defs/refs in generics are mostly missing.
 
-use crate::{id_from_def_id, id_from_hir_id, SaveContext};
+use crate::{id_from_def_id, SaveContext};
 
 use rls_data::{SigElement, Signature};
 
@@ -34,6 +34,7 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir_pretty::id_to_string;
 use rustc_hir_pretty::{bounds_to_string, path_segment_to_string, path_to_string, ty_to_string};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{Ident, Symbol};
 
 pub fn item_signature(item: &hir::Item<'_>, scx: &SaveContext<'_>) -> Option<Signature> {
@@ -71,7 +72,7 @@ pub fn variant_signature(variant: &hir::Variant<'_>, scx: &SaveContext<'_>) -> O
 }
 
 pub fn method_signature(
-    id: hir::HirId,
+    id: hir::OwnerId,
     ident: Ident,
     generics: &hir::Generics<'_>,
     m: &hir::FnSig<'_>,
@@ -84,7 +85,7 @@ pub fn method_signature(
 }
 
 pub fn assoc_const_signature(
-    id: hir::HirId,
+    id: hir::OwnerId,
     ident: Symbol,
     ty: &hir::Ty<'_>,
     default: Option<&hir::Expr<'_>>,
@@ -97,7 +98,7 @@ pub fn assoc_const_signature(
 }
 
 pub fn assoc_type_signature(
-    id: hir::HirId,
+    id: hir::OwnerId,
     ident: Ident,
     bounds: Option<hir::GenericBounds<'_>>,
     default: Option<&hir::Ty<'_>>,
@@ -112,7 +113,8 @@ pub fn assoc_type_signature(
 type Result = std::result::Result<Signature, &'static str>;
 
 trait Sig {
-    fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result;
+    type Parent;
+    fn make(&self, offset: usize, id: Option<Self::Parent>, scx: &SaveContext<'_>) -> Result;
 }
 
 fn extend_sig(
@@ -148,6 +150,7 @@ fn text_sig(text: String) -> Signature {
 }
 
 impl<'hir> Sig for hir::Ty<'hir> {
+    type Parent = hir::HirId;
     fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
         let id = Some(self.hir_id);
         match self.kind {
@@ -326,6 +329,7 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
 }
 
 impl<'hir> Sig for hir::Item<'hir> {
+    type Parent = hir::HirId;
     fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
         let id = Some(self.hir_id());
 
@@ -391,7 +395,7 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
                 text.push_str("fn ");
 
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
 
                 sig.text.push('(');
                 for i in decl.inputs {
@@ -441,7 +445,7 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
             hir::ItemKind::TyAlias(ref ty, ref generics) => {
                 let text = "type ".to_owned();
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
 
                 sig.text.push_str(" = ");
                 let ty = ty.make(offset + sig.text.len(), id, scx)?;
@@ -453,21 +457,21 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
             hir::ItemKind::Enum(_, ref generics) => {
                 let text = "enum ".to_owned();
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
                 sig.text.push_str(" {}");
                 Ok(sig)
             }
             hir::ItemKind::Struct(_, ref generics) => {
                 let text = "struct ".to_owned();
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
                 sig.text.push_str(" {}");
                 Ok(sig)
             }
             hir::ItemKind::Union(_, ref generics) => {
                 let text = "union ".to_owned();
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
                 sig.text.push_str(" {}");
                 Ok(sig)
             }
@@ -483,7 +487,7 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
                 }
                 text.push_str("trait ");
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
 
                 if !bounds.is_empty() {
                     sig.text.push_str(": ");
@@ -498,7 +502,7 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
                 let mut text = String::new();
                 text.push_str("trait ");
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
 
                 if !bounds.is_empty() {
                     sig.text.push_str(" = ");
@@ -532,7 +536,8 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
                     text.push_str(" const");
                 }
 
-                let generics_sig = generics.make(offset + text.len(), id, scx)?;
+                let generics_sig =
+                    generics.make(offset + text.len(), Some(self.owner_id.def_id), scx)?;
                 text.push_str(&generics_sig.text);
 
                 text.push(' ');
@@ -575,6 +580,7 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
 }
 
 impl<'hir> Sig for hir::Path<'hir> {
+    type Parent = hir::HirId;
     fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
         let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
 
@@ -609,7 +615,8 @@ fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) ->
 
 // This does not cover the where clause, which must be processed separately.
 impl<'hir> Sig for hir::Generics<'hir> {
-    fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
+    type Parent = LocalDefId;
+    fn make(&self, offset: usize, _parent_id: Option<LocalDefId>, scx: &SaveContext<'_>) -> Result {
         if self.params.is_empty() {
             return Ok(text_sig(String::new()));
         }
@@ -624,7 +631,7 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
             }
             param_text.push_str(param.name.ident().as_str());
             defs.push(SigElement {
-                id: id_from_hir_id(param.hir_id, scx),
+                id: id_from_def_id(param.def_id.to_def_id()),
                 start: offset + text.len(),
                 end: offset + text.len() + param_text.as_str().len(),
             });
@@ -646,12 +653,13 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
 }
 
 impl<'hir> Sig for hir::FieldDef<'hir> {
-    fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
+    type Parent = LocalDefId;
+    fn make(&self, offset: usize, _parent_id: Option<LocalDefId>, scx: &SaveContext<'_>) -> Result {
         let mut text = String::new();
 
         text.push_str(&self.ident.to_string());
         let defs = Some(SigElement {
-            id: id_from_hir_id(self.hir_id, scx),
+            id: id_from_def_id(self.def_id.to_def_id()),
             start: offset,
             end: offset + text.len(),
         });
@@ -666,13 +674,14 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
 }
 
 impl<'hir> Sig for hir::Variant<'hir> {
-    fn make(&self, offset: usize, parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
+    type Parent = LocalDefId;
+    fn make(&self, offset: usize, parent_id: Option<LocalDefId>, scx: &SaveContext<'_>) -> Result {
         let mut text = self.ident.to_string();
         match self.data {
             hir::VariantData::Struct(fields, r) => {
                 let id = parent_id.ok_or("Missing id for Variant's parent")?;
                 let name_def = SigElement {
-                    id: id_from_hir_id(id, scx),
+                    id: id_from_def_id(id.to_def_id()),
                     start: offset,
                     end: offset + text.len(),
                 };
@@ -693,9 +702,9 @@ fn make(&self, offset: usize, parent_id: Option<hir::HirId>, scx: &SaveContext<'
                 text.push('}');
                 Ok(Signature { text, defs, refs })
             }
-            hir::VariantData::Tuple(fields, id, _) => {
+            hir::VariantData::Tuple(fields, _, def_id) => {
                 let name_def = SigElement {
-                    id: id_from_hir_id(id, scx),
+                    id: id_from_def_id(def_id.to_def_id()),
                     start: offset,
                     end: offset + text.len(),
                 };
@@ -703,7 +712,7 @@ fn make(&self, offset: usize, parent_id: Option<hir::HirId>, scx: &SaveContext<'
                 let mut defs = vec![name_def];
                 let mut refs = vec![];
                 for f in fields {
-                    let field_sig = f.make(offset + text.len(), Some(id), scx)?;
+                    let field_sig = f.make(offset + text.len(), Some(def_id), scx)?;
                     text.push_str(&field_sig.text);
                     text.push_str(", ");
                     defs.extend(field_sig.defs.into_iter());
@@ -712,9 +721,9 @@ fn make(&self, offset: usize, parent_id: Option<hir::HirId>, scx: &SaveContext<'
                 text.push(')');
                 Ok(Signature { text, defs, refs })
             }
-            hir::VariantData::Unit(id, _) => {
+            hir::VariantData::Unit(_, def_id) => {
                 let name_def = SigElement {
-                    id: id_from_hir_id(id, scx),
+                    id: id_from_def_id(def_id.to_def_id()),
                     start: offset,
                     end: offset + text.len(),
                 };
@@ -725,6 +734,7 @@ fn make(&self, offset: usize, parent_id: Option<hir::HirId>, scx: &SaveContext<'
 }
 
 impl<'hir> Sig for hir::ForeignItem<'hir> {
+    type Parent = hir::HirId;
     fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
         let id = Some(self.hir_id());
         match self.kind {
@@ -733,7 +743,7 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
                 text.push_str("fn ");
 
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
 
                 sig.text.push('(');
                 for i in decl.inputs {
@@ -797,25 +807,25 @@ fn name_and_generics(
     mut text: String,
     offset: usize,
     generics: &hir::Generics<'_>,
-    id: hir::HirId,
+    id: hir::OwnerId,
     name: Ident,
     scx: &SaveContext<'_>,
 ) -> Result {
     let name = name.to_string();
     let def = SigElement {
-        id: id_from_hir_id(id, scx),
+        id: id_from_def_id(id.to_def_id()),
         start: offset + text.len(),
         end: offset + text.len() + name.len(),
     };
     text.push_str(&name);
-    let generics: Signature = generics.make(offset + text.len(), Some(id), scx)?;
+    let generics: Signature = generics.make(offset + text.len(), Some(id.def_id), scx)?;
     // FIXME where clause
     let text = format!("{}{}", text, generics.text);
     Ok(extend_sig(generics, text, vec![def], vec![]))
 }
 
 fn make_assoc_type_signature(
-    id: hir::HirId,
+    id: hir::OwnerId,
     ident: Ident,
     bounds: Option<hir::GenericBounds<'_>>,
     default: Option<&hir::Ty<'_>>,
@@ -824,7 +834,7 @@ fn make_assoc_type_signature(
     let mut text = "type ".to_owned();
     let name = ident.to_string();
     let mut defs = vec![SigElement {
-        id: id_from_hir_id(id, scx),
+        id: id_from_def_id(id.to_def_id()),
         start: text.len(),
         end: text.len() + name.len(),
     }];
@@ -837,7 +847,7 @@ fn make_assoc_type_signature(
     }
     if let Some(default) = default {
         text.push_str(" = ");
-        let ty_sig = default.make(text.len(), Some(id), scx)?;
+        let ty_sig = default.make(text.len(), Some(id.into()), scx)?;
         text.push_str(&ty_sig.text);
         defs.extend(ty_sig.defs.into_iter());
         refs.extend(ty_sig.refs.into_iter());
@@ -847,7 +857,7 @@ fn make_assoc_type_signature(
 }
 
 fn make_assoc_const_signature(
-    id: hir::HirId,
+    id: hir::OwnerId,
     ident: Symbol,
     ty: &hir::Ty<'_>,
     default: Option<&hir::Expr<'_>>,
@@ -856,7 +866,7 @@ fn make_assoc_const_signature(
     let mut text = "const ".to_owned();
     let name = ident.to_string();
     let mut defs = vec![SigElement {
-        id: id_from_hir_id(id, scx),
+        id: id_from_def_id(id.to_def_id()),
         start: text.len(),
         end: text.len() + name.len(),
     }];
@@ -864,7 +874,7 @@ fn make_assoc_const_signature(
     text.push_str(&name);
     text.push_str(": ");
 
-    let ty_sig = ty.make(text.len(), Some(id), scx)?;
+    let ty_sig = ty.make(text.len(), Some(id.into()), scx)?;
     text.push_str(&ty_sig.text);
     defs.extend(ty_sig.defs.into_iter());
     refs.extend(ty_sig.refs.into_iter());
@@ -878,7 +888,7 @@ fn make_assoc_const_signature(
 }
 
 fn make_method_signature(
-    id: hir::HirId,
+    id: hir::OwnerId,
     ident: Ident,
     generics: &hir::Generics<'_>,
     m: &hir::FnSig<'_>,
index 8d6758f40f96522d3cbcc9ec79fad3790df563aa..e65d57bb3db3e7737ffbc18b8670df244346be6f 100644 (file)
@@ -18,13 +18,7 @@ pub fn make_filename_string(&self, file: &SourceFile) -> String {
         match &file.name {
             FileName::Real(RealFileName::LocalPath(path)) => {
                 if path.is_absolute() {
-                    self.sess
-                        .source_map()
-                        .path_mapping()
-                        .map_prefix(path.into())
-                        .0
-                        .display()
-                        .to_string()
+                    self.sess.source_map().path_mapping().map_prefix(path).0.display().to_string()
                 } else {
                     self.sess
                         .opts
index 1ccfc59f7a9d61e86b5b9f245cf0f8303f465e6b..c49c5fa990413d1aa3a109612c2773f3b646b65f 100644 (file)
@@ -591,6 +591,24 @@ pub fn source_name(&self) -> FileName {
             Input::Str { ref name, .. } => name.clone(),
         }
     }
+
+    pub fn opt_path(&self) -> Option<&Path> {
+        match self {
+            Input::File(file) => Some(file),
+            Input::Str { name, .. } => match name {
+                FileName::Real(real) => real.local_path(),
+                FileName::QuoteExpansion(_) => None,
+                FileName::Anon(_) => None,
+                FileName::MacroExpansion(_) => None,
+                FileName::ProcMacroSourceCode(_) => None,
+                FileName::CfgSpec(_) => None,
+                FileName::CliCrateAttr(_) => None,
+                FileName::Custom(_) => None,
+                FileName::DocTest(path, _) => Some(path),
+                FileName::InlineAsm(_) => None,
+            },
+        }
+    }
 }
 
 #[derive(Clone, Hash, Debug, HashStable_Generic)]
@@ -715,7 +733,7 @@ pub fn split_dwarf_path(
 pub fn host_triple() -> &'static str {
     // Get the host triple out of the build environment. This ensures that our
     // idea of the host triple is the same as for the set of libraries we've
-    // actually built.  We can't just take LLVM's host triple because they
+    // actually built. We can't just take LLVM's host triple because they
     // normalize all ix86 architectures to i386.
     //
     // Instead of grabbing the host triple (for the current host), we grab (at
@@ -846,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>),
@@ -939,6 +945,7 @@ fn default_configuration(sess: &Session) -> CrateConfig {
     if sess.target.has_thread_local {
         ret.insert((sym::target_thread_local, None));
     }
+    let mut has_atomic = false;
     for (i, align) in [
         (8, layout.i8_align.abi),
         (16, layout.i16_align.abi),
@@ -947,6 +954,7 @@ fn default_configuration(sess: &Session) -> CrateConfig {
         (128, layout.i128_align.abi),
     ] {
         if i >= min_atomic_width && i <= max_atomic_width {
+            has_atomic = true;
             let mut insert_atomic = |s, align: Align| {
                 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
                 if atomic_cas {
@@ -963,6 +971,12 @@ fn default_configuration(sess: &Session) -> CrateConfig {
             }
         }
     }
+    if sess.is_nightly_build() && has_atomic {
+        ret.insert((sym::target_has_atomic_load_store, None));
+        if atomic_cas {
+            ret.insert((sym::target_has_atomic, None));
+        }
+    }
 
     let panic_strategy = sess.panic_strategy();
     ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
@@ -1271,7 +1285,7 @@ pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
 
 // The `opt` local module holds wrappers around the `getopts` API that
 // adds extra rustc-specific metadata to each option; such metadata
-// is exposed by .  The public
+// is exposed by . The public
 // functions below ending with `_u` are the functions that return
 // *unstable* options, i.e., options that are only enabled when the
 // user also passes the `-Z unstable-options` debugging flag.
@@ -2091,7 +2105,7 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
         .map(|s| {
             // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
             // where KIND is one of "dylib", "framework", "static", "link-arg" and
-            // where MODIFIERS are  a comma separated list of supported modifiers
+            // where MODIFIERS are a comma separated list of supported modifiers
             // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
             // with either + or - to indicate whether it is enabled or disabled.
             // The last value specified for a given modifier wins.
@@ -2459,6 +2473,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     let pretty = parse_pretty(&unstable_opts, error_format);
 
+    // query-dep-graph is required if dump-dep-graph is given #106736
+    if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
+        early_error(error_format, "can't dump dependency graph without `-Z query-dep-graph`");
+    }
+
     // Try to find a directory containing the Rust `src`, for more details see
     // the doc comment on the `real_rust_source_base_dir` field.
     let tmp_buf;
@@ -2491,12 +2510,12 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         early_error(error_format, &format!("Current directory is invalid: {e}"));
     });
 
-    let (path, remapped) =
-        FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
+    let remap = FilePathMapping::new(remap_path_prefix.clone());
+    let (path, remapped) = remap.map_prefix(&working_dir);
     let working_dir = if remapped {
-        RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
+        RealFileName::Remapped { virtual_name: path.into_owned(), local_path: Some(working_dir) }
     } else {
-        RealFileName::LocalPath(path)
+        RealFileName::LocalPath(path.into_owned())
     };
 
     Options {
@@ -2554,6 +2573,7 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio
         "hir,typed" => Hir(PpHirMode::Typed),
         "hir-tree" => HirTree,
         "thir-tree" => ThirTree,
+        "thir-flat" => ThirFlat,
         "mir" => Mir,
         "mir-cfg" => MirCFG,
         name => early_error(
@@ -2562,7 +2582,8 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio
                 "argument to `unpretty` must be one of `normal`, `identified`, \
                             `expanded`, `expanded,identified`, `expanded,hygiene`, \
                             `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
-                            `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
+                            `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir` or \
+                            `mir-cfg`; got {name}"
             ),
         ),
     };
@@ -2717,6 +2738,8 @@ pub enum PpMode {
     HirTree,
     /// `-Zunpretty=thir-tree`
     ThirTree,
+    /// `-Zunpretty=`thir-flat`
+    ThirFlat,
     /// `-Zunpretty=mir`
     Mir,
     /// `-Zunpretty=mir-cfg`
@@ -2735,6 +2758,7 @@ pub fn needs_ast_map(&self) -> bool {
             | Hir(_)
             | HirTree
             | ThirTree
+            | ThirFlat
             | Mir
             | MirCFG => true,
         }
@@ -2744,13 +2768,13 @@ pub fn needs_hir(&self) -> bool {
         match *self {
             Source(_) | AstTree(_) => false,
 
-            Hir(_) | HirTree | ThirTree | Mir | MirCFG => true,
+            Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG => true,
         }
     }
 
     pub fn needs_analysis(&self) -> bool {
         use PpMode::*;
-        matches!(*self, Mir | MirCFG | ThirTree)
+        matches!(*self, Mir | MirCFG | ThirTree | ThirFlat)
     }
 }
 
index 7f926f7d8bc4a2cb2cd25871384eff142e0324a8..4ae9a3fae474b3c9a993b97f77cf765de06ed3a7 100644 (file)
@@ -228,7 +228,7 @@ pub trait CrateStore: std::fmt::Debug {
     fn def_path_hash(&self, def: DefId) -> DefPathHash;
 
     // This information is safe to access, since it's hashed as part of the StableCrateId, which
-    // incr.  comp. uses to identify a CrateNum.
+    // incr. comp. uses to identify a CrateNum.
     fn crate_name(&self, cnum: CrateNum) -> Symbol;
     fn stable_crate_id(&self, cnum: CrateNum) -> StableCrateId;
     fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum;
index 6f1b31ff9c3aec9cbce8cb0bf3b2fe053a566ba7..b6a328908ce085834d74cb534ba1503486cca6cf 100644 (file)
@@ -155,7 +155,7 @@ fn current_dll_path() -> Result<PathBuf, String> {
 /// This function checks if sysroot is found using env::args().next(), and if it
 /// is not found, finds sysroot from current rustc_driver dll.
 pub fn get_or_default_sysroot() -> Result<PathBuf, String> {
-    // Follow symlinks.  If the resolved path is relative, make it absolute.
+    // Follow symlinks. If the resolved path is relative, make it absolute.
     fn canonicalize(path: PathBuf) -> PathBuf {
         let path = fs::canonicalize(&path).unwrap_or(path);
         // See comments on this target function, but the gist is that
index 7b5fd6cc2a81d9a0c3bc45c660b34f3c7ec7fec3..0db4d85ff4b679f4934bfe5a0ee7edef577454fe 100644 (file)
@@ -1290,6 +1290,8 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         (default: no)"),
     drop_tracking: bool = (false, parse_bool, [TRACKED],
         "enables drop tracking in generators (default: no)"),
+    drop_tracking_mir: bool = (false, parse_bool, [TRACKED],
+        "enables drop tracking on MIR in generators (default: no)"),
     dual_proc_macros: bool = (false, parse_bool, [TRACKED],
         "load proc macros for both target and host, but only link to the target (default: no)"),
     dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
@@ -1616,6 +1618,8 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         "measure time of each LLVM pass (default: no)"),
     time_passes: bool = (false, parse_bool, [UNTRACKED],
         "measure time of each rustc pass (default: no)"),
+    tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED],
+        "sets a tiny, non-configurable limit for const eval; useful for compiler tests"),
     #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")]
     tls_model: Option<TlsModel> = (None, parse_tls_model, [TRACKED],
         "choose the TLS model to use (`rustc --print tls-models` for details)"),
index 8ee3057de625ef3b08c9faad46c824ae9c685130..c3f0c4b58f57ad61eb04cbad7be79918950af8e3 100644 (file)
@@ -29,9 +29,9 @@ pub fn out_filename(
     out_filename
 }
 
-/// Make sure files are writeable.  Mac, FreeBSD, and Windows system linkers
+/// Make sure files are writeable. Mac, FreeBSD, and Windows system linkers
 /// check this already -- however, the Linux linker will happily overwrite a
-/// read-only file.  We should be consistent.
+/// read-only file. We should be consistent.
 pub fn check_file_is_writeable(file: &Path, sess: &Session) {
     if !is_writeable(file) {
         sess.emit_fatal(FileIsNotWriteable { file });
@@ -45,7 +45,7 @@ fn is_writeable(p: &Path) -> bool {
     }
 }
 
-pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) -> Symbol {
+pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute]) -> Symbol {
     let validate = |s: Symbol, span: Option<Span>| {
         validate_crate_name(sess, s, span);
         s
@@ -71,7 +71,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input)
     if let Some((attr, s)) = attr_crate_name {
         return validate(s, Some(attr.span));
     }
-    if let Input::File(ref path) = *input {
+    if let Input::File(ref path) = sess.io.input {
         if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
             if s.starts_with('-') {
                 sess.emit_err(CrateNameInvalid { s });
index 1b2e8d9dc707bdd60673f4b2d859057899227588..95f199de6ff6ff0c14b781586d20f72c303819b7 100644 (file)
@@ -1,6 +1,7 @@
 use crate::cgu_reuse_tracker::CguReuseTracker;
 use crate::code_stats::CodeStats;
 pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
+use crate::config::Input;
 use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath};
 use crate::errors::{
     BranchProtectionRequiresAArch64, CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers,
@@ -137,6 +138,13 @@ pub struct Limits {
     pub const_eval_limit: Limit,
 }
 
+pub struct CompilerIO {
+    pub input: Input,
+    pub output_dir: Option<PathBuf>,
+    pub output_file: Option<PathBuf>,
+    pub temps_dir: Option<PathBuf>,
+}
+
 /// Represents the data associated with a compilation
 /// session for a single crate.
 pub struct Session {
@@ -147,9 +155,8 @@ pub struct Session {
     pub target_tlib_path: Lrc<SearchPath>,
     pub parse_sess: ParseSess,
     pub sysroot: PathBuf,
-    /// The name of the root source file of the crate, in the local file system.
-    /// `None` means that there is no source file.
-    pub local_crate_source_file: Option<PathBuf>,
+    /// Input, input file path and output file path to this compilation process.
+    pub io: CompilerIO,
 
     crate_types: OnceCell<Vec<CrateType>>,
     /// The `stable_crate_id` is constructed out of the crate name and all the
@@ -197,7 +204,7 @@ pub struct Session {
     pub ctfe_backtrace: Lock<CtfeBacktrace>,
 
     /// This tracks where `-Zunleash-the-miri-inside-of-you` was used to get around a
-    /// const check, optionally with the relevant feature gate.  We use this to
+    /// const check, optionally with the relevant feature gate. We use this to
     /// warn about unleashing, but with a single diagnostic instead of dozens that
     /// drown everything else in noise.
     miri_unleashed_features: Lock<Vec<(Span, Option<Symbol>)>>,
@@ -228,6 +235,11 @@ pub fn miri_unleashed_feature(&self, span: Span, feature_gate: Option<Symbol>) {
         self.miri_unleashed_features.lock().push((span, feature_gate));
     }
 
+    pub fn local_crate_source_file(&self) -> Option<PathBuf> {
+        let path = self.io.input.opt_path()?;
+        Some(self.opts.file_path_mapping().map_prefix(path).0.into_owned())
+    }
+
     fn check_miri_unleashed_features(&self) {
         let unleashed_features = self.miri_unleashed_features.lock();
         if !unleashed_features.is_empty() {
@@ -1298,7 +1310,7 @@ fn default_emitter(
 #[allow(rustc::bad_opt_access)]
 pub fn build_session(
     sopts: config::Options,
-    local_crate_source_file: Option<PathBuf>,
+    io: CompilerIO,
     bundle: Option<Lrc<rustc_errors::FluentBundle>>,
     registry: rustc_errors::registry::Registry,
     driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
@@ -1391,11 +1403,6 @@ pub fn build_session(
         Lrc::new(SearchPath::from_sysroot_and_triple(&sysroot, target_triple))
     };
 
-    let file_path_mapping = sopts.file_path_mapping();
-
-    let local_crate_source_file =
-        local_crate_source_file.map(|path| file_path_mapping.map_prefix(path).0);
-
     let optimization_fuel = Lock::new(OptimizationFuel {
         remaining: sopts.unstable_opts.fuel.as_ref().map_or(0, |&(_, i)| i),
         out_of_fuel: false,
@@ -1427,7 +1434,7 @@ pub fn build_session(
         target_tlib_path,
         parse_sess,
         sysroot,
-        local_crate_source_file,
+        io,
         crate_types: OnceCell::new(),
         stable_crate_id: OnceCell::new(),
         features: OnceCell::new(),
index a9a9a3fbf9d8061c54dbd6fc05d8894d0a339da7..dee823eefde689b013e18644f0572b3bc9363678 100644 (file)
@@ -338,7 +338,7 @@ pub struct HygieneData {
     /// first and then resolved later), so we use an `Option` here.
     local_expn_data: IndexVec<LocalExpnId, Option<ExpnData>>,
     local_expn_hashes: IndexVec<LocalExpnId, ExpnHash>,
-    /// Data and hash information from external crates.  We may eventually want to remove these
+    /// Data and hash information from external crates. We may eventually want to remove these
     /// maps, and fetch the information directly from the other crate's metadata like DefIds do.
     foreign_expn_data: FxHashMap<ExpnId, ExpnData>,
     foreign_expn_hashes: FxHashMap<ExpnId, ExpnHash>,
index fa09b4faa441f3b83d50809c92b426e708784b89..2e339a9d2d2b00eca439bdbd4930e9072c1a0e7a 100644 (file)
@@ -17,7 +17,7 @@
 use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock};
 use std::cmp;
 use std::hash::Hash;
-use std::path::{Path, PathBuf};
+use std::path::{self, Path, PathBuf};
 use std::sync::atomic::Ordering;
 
 use std::fs;
@@ -1071,12 +1071,24 @@ pub fn count_lines(&self) -> usize {
 
     pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool {
         source_file.add_external_src(|| {
-            match source_file.name {
-                FileName::Real(ref name) if let Some(local_path) = name.local_path() => {
-                    self.file_loader.read_file(local_path).ok()
+            let FileName::Real(ref name) = source_file.name else {
+                return None;
+            };
+
+            let local_path: Cow<'_, Path> = match name {
+                RealFileName::LocalPath(local_path) => local_path.into(),
+                RealFileName::Remapped { local_path: Some(local_path), .. } => local_path.into(),
+                RealFileName::Remapped { local_path: None, virtual_name } => {
+                    // The compiler produces better error messages if the sources of dependencies
+                    // are available. Attempt to undo any path mapping so we can find remapped
+                    // dependencies.
+                    // We can only use the heuristic because `add_external_src` checks the file
+                    // content hash.
+                    self.path_mapping.reverse_map_prefix_heuristically(virtual_name)?.into()
                 }
-                _ => None,
-            }
+            };
+
+            self.file_loader.read_file(&local_path).ok()
         })
     }
 
@@ -1138,7 +1150,8 @@ pub fn new(mapping: Vec<(PathBuf, PathBuf)>) -> FilePathMapping {
     /// Applies any path prefix substitution as defined by the mapping.
     /// The return value is the remapped path and a boolean indicating whether
     /// the path was affected by the mapping.
-    pub fn map_prefix(&self, path: PathBuf) -> (PathBuf, bool) {
+    pub fn map_prefix<'a>(&'a self, path: impl Into<Cow<'a, Path>>) -> (Cow<'a, Path>, bool) {
+        let path = path.into();
         if path.as_os_str().is_empty() {
             // Exit early if the path is empty and therefore there's nothing to remap.
             // This is mostly to reduce spam for `RUSTC_LOG=[remap_path_prefix]`.
@@ -1148,7 +1161,10 @@ pub fn map_prefix(&self, path: PathBuf) -> (PathBuf, bool) {
         return remap_path_prefix(&self.mapping, path);
 
         #[instrument(level = "debug", skip(mapping), ret)]
-        fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf, bool) {
+        fn remap_path_prefix<'a>(
+            mapping: &'a [(PathBuf, PathBuf)],
+            path: Cow<'a, Path>,
+        ) -> (Cow<'a, Path>, bool) {
             // NOTE: We are iterating over the mapping entries from last to first
             //       because entries specified later on the command line should
             //       take precedence.
@@ -1163,9 +1179,9 @@ fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf,
                         // in remapped paths down the line.
                         // So, if we have an exact match, we just return that without a call
                         // to `Path::join()`.
-                        to.clone()
+                        to.into()
                     } else {
-                        to.join(rest)
+                        to.join(rest).into()
                     };
                     debug!("Match - remapped");
 
@@ -1183,11 +1199,11 @@ fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf,
     fn map_filename_prefix(&self, file: &FileName) -> (FileName, bool) {
         match file {
             FileName::Real(realfile) if let RealFileName::LocalPath(local_path) = realfile => {
-                let (mapped_path, mapped) = self.map_prefix(local_path.to_path_buf());
+                let (mapped_path, mapped) = self.map_prefix(local_path);
                 let realfile = if mapped {
                     RealFileName::Remapped {
                         local_path: Some(local_path.clone()),
-                        virtual_name: mapped_path,
+                        virtual_name: mapped_path.into_owned(),
                     }
                 } else {
                     realfile.clone()
@@ -1228,14 +1244,17 @@ pub fn to_embeddable_absolute_path(
                 let (new_path, was_remapped) = self.map_prefix(unmapped_file_path);
                 if was_remapped {
                     // It was remapped, so don't modify further
-                    return RealFileName::Remapped { local_path: None, virtual_name: new_path };
+                    return RealFileName::Remapped {
+                        local_path: None,
+                        virtual_name: new_path.into_owned(),
+                    };
                 }
 
                 if new_path.is_absolute() {
                     // No remapping has applied to this path and it is absolute,
                     // so the working directory cannot influence it either, so
                     // we are done.
-                    return RealFileName::LocalPath(new_path);
+                    return RealFileName::LocalPath(new_path.into_owned());
                 }
 
                 debug_assert!(new_path.is_relative());
@@ -1253,12 +1272,12 @@ pub fn to_embeddable_absolute_path(
                             RealFileName::Remapped {
                                 // Erase the actual path
                                 local_path: None,
-                                virtual_name: file_path_abs,
+                                virtual_name: file_path_abs.into_owned(),
                             }
                         } else {
                             // No kind of remapping applied to this path, so
                             // we leave it as it is.
-                            RealFileName::LocalPath(file_path_abs)
+                            RealFileName::LocalPath(file_path_abs.into_owned())
                         }
                     }
                     RealFileName::Remapped {
@@ -1277,4 +1296,43 @@ pub fn to_embeddable_absolute_path(
             }
         }
     }
+
+    /// Attempts to (heuristically) reverse a prefix mapping.
+    ///
+    /// Returns [`Some`] if there is exactly one mapping where the "to" part is
+    /// a prefix of `path` and has at least one non-empty
+    /// [`Normal`](path::Component::Normal) component. The component
+    /// restriction exists to avoid reverse mapping overly generic paths like
+    /// `/` or `.`).
+    ///
+    /// This is a heuristic and not guaranteed to return the actual original
+    /// path! Do not rely on the result unless you have other means to verify
+    /// that the mapping is correct (e.g. by checking the file content hash).
+    #[instrument(level = "debug", skip(self), ret)]
+    fn reverse_map_prefix_heuristically(&self, path: &Path) -> Option<PathBuf> {
+        let mut found = None;
+
+        for (from, to) in self.mapping.iter() {
+            let has_normal_component = to.components().any(|c| match c {
+                path::Component::Normal(s) => !s.is_empty(),
+                _ => false,
+            });
+
+            if !has_normal_component {
+                continue;
+            }
+
+            let Ok(rest) = path.strip_prefix(to) else {
+                continue;
+            };
+
+            if found.is_some() {
+                return None;
+            }
+
+            found = Some(from.join(rest));
+        }
+
+        found
+    }
 }
index 3cab59e8dbe6cf6166b90d65ad62889e852782a7..686b3b00d7047a7120717418ce5106c118599408 100644 (file)
@@ -344,6 +344,10 @@ fn map_path_prefix(mapping: &FilePathMapping, p: &str) -> String {
     mapping.map_prefix(path(p)).0.to_string_lossy().to_string()
 }
 
+fn reverse_map_prefix(mapping: &FilePathMapping, p: &str) -> Option<String> {
+    mapping.reverse_map_prefix_heuristically(&path(p)).map(|q| q.to_string_lossy().to_string())
+}
+
 #[test]
 fn path_prefix_remapping() {
     // Relative to relative
@@ -387,7 +391,7 @@ fn path_prefix_remapping_expand_to_absolute() {
     let working_directory = path("/foo");
     let working_directory = RealFileName::Remapped {
         local_path: Some(working_directory.clone()),
-        virtual_name: mapping.map_prefix(working_directory).0,
+        virtual_name: mapping.map_prefix(working_directory).0.into_owned(),
     };
 
     assert_eq!(working_directory.remapped_path_if_available(), path("FOO"));
@@ -480,6 +484,45 @@ fn path_prefix_remapping_expand_to_absolute() {
     );
 }
 
+#[test]
+fn path_prefix_remapping_reverse() {
+    // Ignores options without alphanumeric chars.
+    {
+        let mapping =
+            &FilePathMapping::new(vec![(path("abc"), path("/")), (path("def"), path("."))]);
+
+        assert_eq!(reverse_map_prefix(mapping, "/hello.rs"), None);
+        assert_eq!(reverse_map_prefix(mapping, "./hello.rs"), None);
+    }
+
+    // Returns `None` if multiple options match.
+    {
+        let mapping = &FilePathMapping::new(vec![
+            (path("abc"), path("/redacted")),
+            (path("def"), path("/redacted")),
+        ]);
+
+        assert_eq!(reverse_map_prefix(mapping, "/redacted/hello.rs"), None);
+    }
+
+    // Distinct reverse mappings.
+    {
+        let mapping = &FilePathMapping::new(vec![
+            (path("abc"), path("/redacted")),
+            (path("def/ghi"), path("/fake/dir")),
+        ]);
+
+        assert_eq!(
+            reverse_map_prefix(mapping, "/redacted/path/hello.rs"),
+            Some(path_str("abc/path/hello.rs"))
+        );
+        assert_eq!(
+            reverse_map_prefix(mapping, "/fake/dir/hello.rs"),
+            Some(path_str("def/ghi/hello.rs"))
+        );
+    }
+}
+
 #[test]
 fn test_next_point() {
     let sm = SourceMap::new(FilePathMapping::empty());
index 706002f79b1fb98163ff6e2abe678f0fdabe443c..f1119214be44db4e7d61615bfa9f488253c2f634 100644 (file)
         Capture,
         Center,
         Clone,
+        Context,
         Continue,
         Copy,
         Count,
         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,
         mul,
         mul_assign,
         mul_with_overflow,
+        multiple_supertrait_upcastable,
         must_not_suspend,
         must_use,
         naked,
index 0759b95bd94c8f5e4d930f7d5f50224ef30e5611..c9b4ab0a38d6ee185538827ce623ac2c8f6b0424 100644 (file)
@@ -640,6 +640,7 @@ fn encode_ty<'tcx>(
         ty::Bound(..)
         | ty::Error(..)
         | ty::GeneratorWitness(..)
+        | ty::GeneratorWitnessMIR(..)
         | ty::Infer(..)
         | ty::Alias(..)
         | ty::Param(..)
@@ -793,6 +794,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
         ty::Bound(..)
         | ty::Error(..)
         | ty::GeneratorWitness(..)
+        | ty::GeneratorWitnessMIR(..)
         | ty::Infer(..)
         | ty::Alias(..)
         | ty::Param(..)
index 0d446d654dc5ce99ede511fb1a4c6f7fc149f279..00d1ff5ceedf7cc326dd1bc610b47b48f8cc962c 100644 (file)
@@ -490,6 +490,7 @@ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
             }
 
             ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"),
+            ty::GeneratorWitnessMIR(..) => bug!("symbol_names: unexpected `GeneratorWitnessMIR`"),
         }
 
         // Only cache types that do not refer to an enclosing
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 7f01f33d39c6cace7bfcb13e9fccd35963ae45f1..70cd883be09b3d7d57989931b1a58d8a101ab585 100644 (file)
@@ -462,7 +462,7 @@ pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Sel
     }
 
     /// Returns a suggested template modifier to use for this type and an
-    /// example of a  register named formatted with it.
+    /// example of a register named formatted with it.
     ///
     /// Such suggestions are useful if a type smaller than the full register
     /// size is used and a modifier can be used to point to the subregister of
index e72cab629ff19058cd332c33689fc851ee263cc4..b69ade7e4aa08eee89426153ea3d6b427e62af92 100644 (file)
@@ -12,7 +12,7 @@ pub fn target() -> Target {
 
     Target {
         // Clang automatically chooses a more specific target based on
-        // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
+        // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
         // correctly, we do too.
         llvm_target: macos_llvm_target(arch).into(),
         pointer_width: 64,
index 2b00cda44b511372a33ba51c89c95eb721fcd249..4d03747d0165f698ae7ce3d7867f27110b3316d1 100644 (file)
@@ -6,7 +6,7 @@ pub fn opts(endian: Endian) -> TargetOptions {
         allow_asm: true,
         endian,
         linker_flavor: LinkerFlavor::Bpf,
-        atomic_cas: true,
+        atomic_cas: false,
         dynamic_linking: true,
         no_builtins: true,
         panic_strategy: PanicStrategy::Abort,
index ad22467ba9c8970ad4cdf13b804d648b307f6cfb..b5103d15db695d95de98d7ebc8b4936f832f3446 100644 (file)
@@ -12,7 +12,7 @@ pub fn target() -> Target {
 
     Target {
         // Clang automatically chooses a more specific target based on
-        // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
+        // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
         // correctly, we do too.
         //
         // While ld64 doesn't understand i686, LLVM does.
index 8ac351584434848f258c452b37cafa6964ba8084..e63e789752bc74eed91ae7601bc287bfe8e0d024 100644 (file)
@@ -5,8 +5,8 @@ pub fn opts() -> TargetOptions {
         LinkerFlavor::Unix(Cc::Yes),
         &[
             // The illumos libc contains a stack unwinding implementation, as
-            // does libgcc_s.  The latter implementation includes several
-            // additional symbols that are not always in base libc.  To force
+            // does libgcc_s. The latter implementation includes several
+            // additional symbols that are not always in base libc. To force
             // the consistent use of just one unwinder, we ensure libc appears
             // after libgcc_s in the NEEDED list for the resultant binary by
             // ignoring any attempts to add it as a dynamic dependency until the
@@ -17,7 +17,7 @@ pub fn opts() -> TargetOptions {
             "-lc",
             // LLVM will insert calls to the stack protector functions
             // "__stack_chk_fail" and "__stack_chk_guard" into code in native
-            // object files.  Some platforms include these symbols directly in
+            // object files. Some platforms include these symbols directly in
             // libc, but at least historically these have been provided in
             // libssp.so on illumos and Solaris systems.
             "-lssp",
@@ -40,16 +40,16 @@ pub fn opts() -> TargetOptions {
         // cleanup handlers (in C, this would be something along the lines of:
         // void register_callback(void (*fn)(void *), void *arg);
         // (see src/libstd/sys/unix/fast_thread_local.rs) that is currently
-        // missing in illumos.  For now at least, we must fallback to using
+        // missing in illumos. For now at least, we must fallback to using
         // pthread_{get,set}specific.
         //has_thread_local: true,
 
         // FIXME: Currently, rust is invoking cc to link, which ends up
-        // causing these to get included twice.  We should eventually transition
+        // causing these to get included twice. We should eventually transition
         // to having rustc invoke ld directly, in which case these will need to
         // be uncommented.
         //
-        // We want XPG6 behavior from libc and libm.  See standards(5)
+        // We want XPG6 behavior from libc and libm. See standards(5)
         //pre_link_objects_exe: vec![
         //    "/usr/lib/amd64/values-Xc.o".into(),
         //    "/usr/lib/amd64/values-xpg6.o".into(),
index 1e80b8b759db4e008a3cf831dd1117eab2f6e2b6..a094c2c545269bede5d2eb6764e3eb2df611c51b 100644 (file)
@@ -2622,7 +2622,7 @@ pub fn expect_builtin(target_triple: &TargetTriple) -> Target {
     /// Search for a JSON file specifying the given target triple.
     ///
     /// If none is found in `$RUST_TARGET_PATH`, look for a file called `target.json` inside the
-    /// sysroot under the target-triple's `rustlib` directory.  Note that it could also just be a
+    /// sysroot under the target-triple's `rustlib` directory. Note that it could also just be a
     /// bare filename already, so also check for that. If one of the hardcoded targets we know
     /// about, just return it directly.
     ///
index cda88de0ea40693558af4084af4a49adcaa33ea4..f2c722b9a89da076e450e6bc8ceda7ce9fe3d67b 100644 (file)
@@ -1,5 +1,5 @@
 use crate::abi::Endian;
-use crate::spec::{StackProbeType, Target};
+use crate::spec::{SanitizerSet, StackProbeType, Target};
 
 pub fn target() -> Target {
     let mut base = super::linux_gnu_base::opts();
@@ -13,6 +13,8 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     base.min_global_align = Some(16);
     base.stack_probes = StackProbeType::Inline;
+    base.supported_sanitizers =
+        SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
 
     Target {
         llvm_target: "s390x-unknown-linux-gnu".into(),
index 91e63aee5e49020211443eec54f3c776b0be92e7..8fe9d023c527e824a7d8803f4abecfe8603328ac 100644 (file)
@@ -1,5 +1,5 @@
 use crate::abi::Endian;
-use crate::spec::{StackProbeType, Target};
+use crate::spec::{SanitizerSet, StackProbeType, Target};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
@@ -14,6 +14,8 @@ pub fn target() -> Target {
     base.min_global_align = Some(16);
     base.static_position_independent_executables = true;
     base.stack_probes = StackProbeType::Inline;
+    base.supported_sanitizers =
+        SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
 
     Target {
         llvm_target: "s390x-unknown-linux-musl".into(),
index 440194ef216bf9f20232b02dbe0519c8dac22b40..4d2bc98ab7831fff14840eaf35281f25d1e6143c 100644 (file)
@@ -15,7 +15,7 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "E-m:e-i64:64-n32:64-S128".into(),
         // Use "sparc64" instead of "sparcv9" here, since the former is already
-        // used widely in the source base.  If we ever needed ABI
+        // used widely in the source base. If we ever needed ABI
         // differentiation from the sparc64, we could, but that would probably
         // just be confusing.
         arch: "sparc64".into(),
index 9a3e7a8050025c01cc63e69238ad78756b736213..e90bda9c9a8718683ddc2cec4c0ed46fed7626bf 100644 (file)
@@ -14,7 +14,7 @@ pub fn target() -> Target {
 
     Target {
         // Clang automatically chooses a more specific target based on
-        // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
+        // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
         // correctly, we do too.
         llvm_target: macos_llvm_target(arch).into(),
         pointer_width: 64,
index 67613e1a4ebc01e31aacb60aead8538012423dd0..90d879976c260cb33d84020b09a0ff33c9423d71 100644 (file)
@@ -19,6 +19,7 @@ rustc_infer = { path = "../rustc_infer" }
 rustc_lint_defs = { path = "../rustc_lint_defs" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_query_system = { path = "../rustc_query_system" }
+rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
index 081ac966c696193252a769e5944aae4ac38c9090..6fa0941036390a675beafe5305269c0e9633c740 100644 (file)
@@ -21,6 +21,7 @@
 #![feature(never_type)]
 #![feature(result_option_inspect)]
 #![feature(type_alias_impl_trait)]
+#![feature(min_specialization)]
 #![recursion_limit = "512"] // For rustdoc
 
 #[macro_use]
index e9ddad11ff23e5707ad6297186d93846588e1e03..e44fd82ba22362d1b26e06032c275027e36c39a2 100644 (file)
@@ -1,38 +1,87 @@
 //! Code shared by trait and projection goals for candidate assembly.
 
 use super::infcx_ext::InferCtxtExt;
-use super::{
-    fixme_instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty,
-    EvalCtxt, Goal,
-};
+#[cfg(doc)]
+use super::trait_goals::structural_traits::*;
+use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::infer::{
-    canonical::{CanonicalVarValues, OriginalQueryValues},
-    InferCtxt,
-};
 use rustc_infer::traits::query::NoSolution;
+use rustc_infer::traits::util::elaborate_predicates;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::DUMMY_SP;
 use std::fmt::Debug;
 
 /// A candidate is a possible way to prove a goal.
 ///
 /// It consists of both the `source`, which describes how that goal would be proven,
 /// and the `result` when using the given `source`.
-///
-/// For the list of possible candidates, please look at the documentation of
-/// [super::trait_goals::CandidateSource] and [super::project_goals::CandidateSource].
 #[derive(Debug, Clone)]
-pub(super) struct Candidate<'tcx, G: GoalKind<'tcx>> {
-    pub(super) source: G::CandidateSource,
+pub(super) struct Candidate<'tcx> {
+    pub(super) source: CandidateSource,
     pub(super) result: CanonicalResponse<'tcx>,
 }
 
-pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy {
-    type CandidateSource: Debug + Copy;
+/// Possible ways the given goal can be proven.
+#[derive(Debug, Clone, Copy)]
+pub(super) enum CandidateSource {
+    /// A user written impl.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// fn main() {
+    ///     let x: Vec<u32> = Vec::new();
+    ///     // This uses the impl from the standard library to prove `Vec<T>: Clone`.
+    ///     let y = x.clone();
+    /// }
+    /// ```
+    Impl(DefId),
+    /// A builtin impl generated by the compiler. When adding a new special
+    /// trait, try to use actual impls whenever possible. Builtin impls should
+    /// only be used in cases where the impl cannot be manually be written.
+    ///
+    /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
+    /// For a list of all traits with builtin impls, check out the
+    /// [`EvalCtxt::assemble_builtin_impl_candidates`] method. Not
+    BuiltinImpl,
+    /// An assumption from the environment.
+    ///
+    /// More precicely we've used the `n-th` assumption in the `param_env`.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// fn is_clone<T: Clone>(x: T) -> (T, T) {
+    ///     // This uses the assumption `T: Clone` from the `where`-bounds
+    ///     // to prove `T: Clone`.
+    ///     (x.clone(), x)
+    /// }
+    /// ```
+    ParamEnv(usize),
+    /// If the self type is an alias type, e.g. an opaque type or a projection,
+    /// we know the bounds on that alias to hold even without knowing its concrete
+    /// underlying type.
+    ///
+    /// More precisely this candidate is using the `n-th` bound in the `item_bounds` of
+    /// the self type.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// trait Trait {
+    ///     type Assoc: Clone;
+    /// }
+    ///
+    /// fn foo<T: Trait>(x: <T as Trait>::Assoc) {
+    ///     // We prove `<T as Trait>::Assoc` by looking at the bounds on `Assoc` in
+    ///     // in the trait definition.
+    ///     let _y = x.clone();
+    /// }
+    /// ```
+    AliasBound,
+}
 
+pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
     fn self_ty(self) -> Ty<'tcx>;
 
     fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self;
@@ -40,47 +89,124 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy {
     fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
 
     fn consider_impl_candidate(
-        acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
+        ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
         impl_def_id: DefId,
-    );
-}
+    ) -> QueryResult<'tcx>;
 
-/// An abstraction which correctly deals with the canonical results for candidates.
-///
-/// It also deduplicates the behavior between trait and projection predicates.
-pub(super) struct AssemblyCtxt<'a, 'tcx, G: GoalKind<'tcx>> {
-    pub(super) cx: &'a mut EvalCtxt<'tcx>,
-    pub(super) infcx: &'a InferCtxt<'tcx>,
-    var_values: CanonicalVarValues<'tcx>,
-    candidates: Vec<Candidate<'tcx, G>>,
-}
+    fn consider_assumption(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        assumption: ty::Predicate<'tcx>,
+    ) -> QueryResult<'tcx>;
 
-impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> {
-    pub(super) fn assemble_and_evaluate_candidates(
-        cx: &'a mut EvalCtxt<'tcx>,
-        goal: CanonicalGoal<'tcx, G>,
-    ) -> Vec<Candidate<'tcx, G>> {
-        let (ref infcx, goal, var_values) =
-            cx.tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
-        let mut acx = AssemblyCtxt { cx, infcx, var_values, candidates: Vec::new() };
+    // A type implements an `auto trait` if its components do as well. These components
+    // are given by built-in rules from [`instantiate_constituent_tys_for_auto_trait`].
+    fn consider_auto_trait_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
 
-        acx.assemble_candidates_after_normalizing_self_ty(goal);
+    // A trait alias holds if the RHS traits and `where` clauses hold.
+    fn consider_trait_alias_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
 
-        acx.assemble_impl_candidates(goal);
+    // A type is `Copy` or `Clone` if its components are `Sized`. These components
+    // are given by built-in rules from [`instantiate_constituent_tys_for_sized_trait`].
+    fn consider_builtin_sized_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
 
-        acx.candidates
-    }
+    // A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. These
+    // components are given by built-in rules from [`instantiate_constituent_tys_for_copy_clone_trait`].
+    fn consider_builtin_copy_clone_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
+    // A type is `PointerSized` if we can compute its layout, and that layout
+    // matches the layout of `usize`.
+    fn consider_builtin_pointer_sized_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
+    // A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
+    // family of traits where `A` is given by the signature of the type.
+    fn consider_builtin_fn_trait_candidates(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        kind: ty::ClosureKind,
+    ) -> QueryResult<'tcx>;
 
-    pub(super) fn try_insert_candidate(
+    // `Tuple` is implemented if the `Self` type is a tuple.
+    fn consider_builtin_tuple_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
+    // `Pointee` is always implemented.
+    //
+    // See the projection implementation for the `Metadata` types for all of
+    // the built-in types. For structs, the metadata type is given by the struct
+    // tail.
+    fn consider_builtin_pointee_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
+    // A generator (that comes from an `async` desugaring) is known to implement
+    // `Future<Output = O>`, where `O` is given by the generator's return type
+    // that was computed during type-checking.
+    fn consider_builtin_future_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
+    // A generator (that doesn't come from an `async` desugaring) is known to
+    // implement `Generator<R, Yield = Y, Return = O>`, given the resume, yield,
+    // and return types of the generator computed during type-checking.
+    fn consider_builtin_generator_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+}
+
+impl<'tcx> EvalCtxt<'_, 'tcx> {
+    pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
         &mut self,
-        source: G::CandidateSource,
-        certainty: Certainty,
-    ) {
-        match self.infcx.make_canonical_response(self.var_values.clone(), certainty) {
-            Ok(result) => self.candidates.push(Candidate { source, result }),
-            Err(NoSolution) => debug!(?source, ?certainty, "failed leakcheck"),
+        goal: Goal<'tcx, G>,
+    ) -> Vec<Candidate<'tcx>> {
+        debug_assert_eq!(goal, self.infcx.resolve_vars_if_possible(goal));
+
+        // HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule,
+        // object bound, alias bound, etc. We are unable to determine this until we can at
+        // least structually resolve the type one layer.
+        if goal.predicate.self_ty().is_ty_var() {
+            return vec![Candidate {
+                source: CandidateSource::BuiltinImpl,
+                result: self.make_canonical_response(Certainty::AMBIGUOUS).unwrap(),
+            }];
         }
+
+        let mut candidates = Vec::new();
+
+        self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates);
+
+        self.assemble_impl_candidates(goal, &mut candidates);
+
+        self.assemble_builtin_impl_candidates(goal, &mut candidates);
+
+        self.assemble_param_env_candidates(goal, &mut candidates);
+
+        self.assemble_alias_bound_candidates(goal, &mut candidates);
+
+        self.assemble_object_bound_candidates(goal, &mut candidates);
+
+        candidates
     }
 
     /// If the self type of a goal is a projection, computing the relevant candidates is difficult.
@@ -88,8 +214,12 @@ pub(super) fn try_insert_candidate(
     /// To deal with this, we first try to normalize the self type and add the candidates for the normalized
     /// self type to the list of candidates in case that succeeds. Note that we can't just eagerly return in
     /// this case as projections as self types add `
-    fn assemble_candidates_after_normalizing_self_ty(&mut self, goal: Goal<'tcx, G>) {
-        let tcx = self.cx.tcx;
+    fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>(
+        &mut self,
+        goal: Goal<'tcx, G>,
+        candidates: &mut Vec<Candidate<'tcx>>,
+    ) {
+        let tcx = self.tcx();
         // FIXME: We also have to normalize opaque types, not sure where to best fit that in.
         let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else {
             return
@@ -103,48 +233,200 @@ fn assemble_candidates_after_normalizing_self_ty(&mut self, goal: Goal<'tcx, G>)
                     term: normalized_ty.into(),
                 }),
             );
-            let normalization_certainty =
-                match self.cx.evaluate_goal(&self.infcx, normalizes_to_goal) {
-                    Ok((_, certainty)) => certainty,
-                    Err(NoSolution) => return,
-                };
+            let normalization_certainty = match self.evaluate_goal(normalizes_to_goal) {
+                Ok((_, certainty)) => certainty,
+                Err(NoSolution) => return,
+            };
+            let normalized_ty = self.infcx.resolve_vars_if_possible(normalized_ty);
 
             // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate.
-            // This doesn't work as long as we use `CandidateSource` in both winnowing and to resolve associated items.
+            // This doesn't work as long as we use `CandidateSource` in winnowing.
             let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
-            let mut orig_values = OriginalQueryValues::default();
-            let goal = self.infcx.canonicalize_query(goal, &mut orig_values);
-            let normalized_candidates =
-                AssemblyCtxt::assemble_and_evaluate_candidates(self.cx, goal);
-
-            // Map each candidate from being canonical wrt the current inference context to being
-            // canonical wrt the caller.
-            for Candidate { source, result } in normalized_candidates {
-                self.infcx.probe(|_| {
-                    let candidate_certainty = fixme_instantiate_canonical_query_response(
-                        &self.infcx,
-                        &orig_values,
-                        result,
-                    );
-
-                    // FIXME: This is a bit scary if the `normalizes_to_goal` overflows.
-                    //
-                    // If we have an ambiguous candidate it hides that normalization
-                    // caused an overflow which may cause issues.
-                    self.try_insert_candidate(
-                        source,
-                        normalization_certainty.unify_and(candidate_certainty),
-                    )
-                })
+            let normalized_candidates = self.assemble_and_evaluate_candidates(goal);
+            for mut normalized_candidate in normalized_candidates {
+                normalized_candidate.result =
+                    normalized_candidate.result.unchecked_map(|mut response| {
+                        // FIXME: This currently hides overflow in the normalization step of the self type
+                        // which is probably wrong. Maybe `unify_and` should actually keep overflow as
+                        // we treat it as non-fatal anyways.
+                        response.certainty = response.certainty.unify_and(normalization_certainty);
+                        response
+                    });
+                candidates.push(normalized_candidate);
             }
         })
     }
 
-    fn assemble_impl_candidates(&mut self, goal: Goal<'tcx, G>) {
-        self.cx.tcx.for_each_relevant_impl(
-            goal.predicate.trait_def_id(self.cx.tcx),
+    fn assemble_impl_candidates<G: GoalKind<'tcx>>(
+        &mut self,
+        goal: Goal<'tcx, G>,
+        candidates: &mut Vec<Candidate<'tcx>>,
+    ) {
+        let tcx = self.tcx();
+        tcx.for_each_relevant_impl(
+            goal.predicate.trait_def_id(tcx),
             goal.predicate.self_ty(),
-            |impl_def_id| G::consider_impl_candidate(self, goal, impl_def_id),
+            |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) {
+                Ok(result) => candidates
+                    .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
+                Err(NoSolution) => (),
+            },
         );
     }
+
+    fn assemble_builtin_impl_candidates<G: GoalKind<'tcx>>(
+        &mut self,
+        goal: Goal<'tcx, G>,
+        candidates: &mut Vec<Candidate<'tcx>>,
+    ) {
+        let lang_items = self.tcx().lang_items();
+        let trait_def_id = goal.predicate.trait_def_id(self.tcx());
+        let result = if self.tcx().trait_is_auto(trait_def_id) {
+            G::consider_auto_trait_candidate(self, goal)
+        } else if self.tcx().trait_is_alias(trait_def_id) {
+            G::consider_trait_alias_candidate(self, goal)
+        } else if lang_items.sized_trait() == Some(trait_def_id) {
+            G::consider_builtin_sized_candidate(self, goal)
+        } else if lang_items.copy_trait() == Some(trait_def_id)
+            || lang_items.clone_trait() == Some(trait_def_id)
+        {
+            G::consider_builtin_copy_clone_candidate(self, goal)
+        } else if lang_items.pointer_sized() == Some(trait_def_id) {
+            G::consider_builtin_pointer_sized_candidate(self, goal)
+        } else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) {
+            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)
+        };
+
+        match result {
+            Ok(result) => {
+                candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
+            }
+            Err(NoSolution) => (),
+        }
+    }
+
+    fn assemble_param_env_candidates<G: GoalKind<'tcx>>(
+        &mut self,
+        goal: Goal<'tcx, G>,
+        candidates: &mut Vec<Candidate<'tcx>>,
+    ) {
+        for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
+            match G::consider_assumption(self, goal, assumption) {
+                Ok(result) => {
+                    candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
+                }
+                Err(NoSolution) => (),
+            }
+        }
+    }
+
+    fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>(
+        &mut self,
+        goal: Goal<'tcx, G>,
+        candidates: &mut Vec<Candidate<'tcx>>,
+    ) {
+        let alias_ty = match goal.predicate.self_ty().kind() {
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Adt(_, _)
+            | ty::Foreign(_)
+            | ty::Str
+            | ty::Array(_, _)
+            | ty::Slice(_)
+            | ty::RawPtr(_)
+            | ty::Ref(_, _, _)
+            | ty::FnDef(_, _)
+            | ty::FnPtr(_)
+            | ty::Dynamic(..)
+            | ty::Closure(..)
+            | ty::Generator(..)
+            | ty::GeneratorWitness(_)
+            | ty::GeneratorWitnessMIR(..)
+            | ty::Never
+            | ty::Tuple(_)
+            | ty::Param(_)
+            | ty::Placeholder(..)
+            | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+            | ty::Error(_) => return,
+            ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
+            | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
+            ty::Alias(_, alias_ty) => alias_ty,
+        };
+
+        for (assumption, _) in self
+            .tcx()
+            .bound_explicit_item_bounds(alias_ty.def_id)
+            .subst_iter_copied(self.tcx(), alias_ty.substs)
+        {
+            match G::consider_assumption(self, goal, assumption) {
+                Ok(result) => {
+                    candidates.push(Candidate { source: CandidateSource::AliasBound, result })
+                }
+                Err(NoSolution) => (),
+            }
+        }
+    }
+
+    fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
+        &mut self,
+        goal: Goal<'tcx, G>,
+        candidates: &mut Vec<Candidate<'tcx>>,
+    ) {
+        let self_ty = goal.predicate.self_ty();
+        let bounds = match *self_ty.kind() {
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Adt(_, _)
+            | ty::Foreign(_)
+            | ty::Str
+            | ty::Array(_, _)
+            | ty::Slice(_)
+            | ty::RawPtr(_)
+            | ty::Ref(_, _, _)
+            | ty::FnDef(_, _)
+            | ty::FnPtr(_)
+            | ty::Alias(..)
+            | ty::Closure(..)
+            | ty::Generator(..)
+            | ty::GeneratorWitness(_)
+            | ty::GeneratorWitnessMIR(..)
+            | ty::Never
+            | ty::Tuple(_)
+            | ty::Param(_)
+            | ty::Placeholder(..)
+            | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+            | ty::Error(_) => return,
+            ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
+            | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
+            ty::Dynamic(bounds, ..) => bounds,
+        };
+
+        let tcx = self.tcx();
+        for assumption in
+            elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)))
+        {
+            match G::consider_assumption(self, goal, assumption.predicate) {
+                Ok(result) => {
+                    candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
+                }
+                Err(NoSolution) => (),
+            }
+        }
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/cache.rs b/compiler/rustc_trait_selection/src/solve/cache.rs
deleted file mode 100644 (file)
index 993b798..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-//! This module both handles the global cache which stores "finished" goals,
-//! and the provisional cache which contains partially computed goals.
-//!
-//! The provisional cache is necessary when dealing with coinductive cycles.
-//!
-//! For more information about the provisional cache and coinduction in general,
-//! check out the relevant section of the rustc-dev-guide.
-//!
-//! FIXME(@lcnr): Write that section, feel free to ping me if you need help here
-//! before then or if I still haven't done that before January 2023.
-use super::overflow::OverflowData;
-use super::CanonicalGoal;
-use super::{EvalCtxt, QueryResult};
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::ty::TyCtxt;
-use std::{cmp::Ordering, collections::hash_map::Entry};
-
-#[derive(Debug, Clone)]
-struct ProvisionalEntry<'tcx> {
-    // In case we have a coinductive cycle, this is the
-    // the currently least restrictive result of this goal.
-    response: QueryResult<'tcx>,
-    // The lowest element on the stack on which this result
-    // relies on. Starts out as just being the depth at which
-    // we've proven this obligation, but gets lowered to the
-    // depth of another goal if we rely on it in a cycle.
-    depth: usize,
-}
-
-struct StackElem<'tcx> {
-    goal: CanonicalGoal<'tcx>,
-    has_been_used: bool,
-}
-
-/// The cache used for goals which are currently in progress or which depend
-/// on in progress results.
-///
-/// Once we're done with a goal we can store it in the global trait solver
-/// cache of the `TyCtxt`. For goals which we're currently proving, or which
-/// have only been proven via a coinductive cycle using a goal still on our stack
-/// we have to use this separate data structure.
-///
-/// The current data structure is not perfect, so there may still be room for
-/// improvement here. We have the following requirements:
-///
-/// ## Is there is a provisional entry for the given goal:
-///
-/// ```ignore (for syntax highlighting)
-/// self.entries.get(goal)
-/// ```
-///
-/// ## Get all goals on the stack involved in a cycle:
-///
-/// ```ignore (for syntax highlighting)
-/// let entry = self.entries.get(goal).unwrap();
-/// let involved_goals = self.stack.iter().skip(entry.depth);
-/// ```
-///
-/// ## Capping the depth of all entries
-///
-/// Needed whenever we encounter a cycle. The current implementation always
-/// iterates over all entries instead of only the ones with a larger depth.
-/// Changing this may result in notable performance improvements.
-///
-/// ```ignore (for syntax highlighting)
-/// let cycle_depth = self.entries.get(goal).unwrap().depth;
-/// for e in &mut self.entries {
-///     e.depth = e.depth.min(cycle_depth);
-/// }
-/// ```
-///
-/// ## Checking whether we have to rerun the current goal
-///
-/// A goal has to be rerun if its provisional result was used in a cycle
-/// and that result is different from its final result. We update
-/// [StackElem::has_been_used] for the deepest stack element involved in a cycle.
-///
-/// ## Moving all finished goals into the global cache
-///
-/// If `stack_elem.has_been_used` is true, iterate over all entries, moving the ones
-/// with equal depth. If not, simply move this single entry.
-pub(super) struct ProvisionalCache<'tcx> {
-    stack: Vec<StackElem<'tcx>>,
-    entries: FxHashMap<CanonicalGoal<'tcx>, ProvisionalEntry<'tcx>>,
-}
-
-impl<'tcx> ProvisionalCache<'tcx> {
-    pub(super) fn empty() -> ProvisionalCache<'tcx> {
-        ProvisionalCache { stack: Vec::new(), entries: Default::default() }
-    }
-
-    pub(super) fn current_depth(&self) -> usize {
-        self.stack.len()
-    }
-}
-
-impl<'tcx> EvalCtxt<'tcx> {
-    /// Tries putting the new goal on the stack, returning an error if it is already cached.
-    ///
-    /// This correctly updates the provisional cache if there is a cycle.
-    pub(super) fn try_push_stack(
-        &mut self,
-        goal: CanonicalGoal<'tcx>,
-    ) -> Result<(), QueryResult<'tcx>> {
-        // FIXME: start by checking the global cache
-
-        // Look at the provisional cache to check for cycles.
-        let cache = &mut self.provisional_cache;
-        match cache.entries.entry(goal) {
-            // No entry, simply push this goal on the stack after dealing with overflow.
-            Entry::Vacant(v) => {
-                if self.overflow_data.has_overflow(cache.stack.len()) {
-                    return Err(self.deal_with_overflow());
-                }
-
-                v.insert(ProvisionalEntry {
-                    response: fixme_response_yes_no_constraints(),
-                    depth: cache.stack.len(),
-                });
-                cache.stack.push(StackElem { goal, has_been_used: false });
-                Ok(())
-            }
-            // We have a nested goal which relies on a goal `root` deeper in the stack.
-            //
-            // We first store that we may have to rerun `evaluate_goal` for `root` in case the
-            // provisional response is not equal to the final response. We also update the depth
-            // of all goals which recursively depend on our current goal to depend on `root`
-            // instead.
-            //
-            // Finally we can return either the provisional response for that goal if we have a
-            // coinductive cycle or an ambiguous result if the cycle is inductive.
-            Entry::Occupied(entry) => {
-                // FIXME: `ProvisionalEntry` should be `Copy`.
-                let entry = entry.get().clone();
-                cache.stack[entry.depth].has_been_used = true;
-                for provisional_entry in cache.entries.values_mut() {
-                    provisional_entry.depth = provisional_entry.depth.min(entry.depth);
-                }
-
-                // NOTE: The goals on the stack aren't the only goals involved in this cycle.
-                // We can also depend on goals which aren't part of the stack but coinductively
-                // depend on the stack themselves. We already checked whether all the goals
-                // between these goals and their root on the stack. This means that as long as
-                // each goal in a cycle is checked for coinductivity by itself simply checking
-                // the stack is enough.
-                if cache.stack[entry.depth..]
-                    .iter()
-                    .all(|g| g.goal.value.predicate.is_coinductive(self.tcx))
-                {
-                    Err(entry.response)
-                } else {
-                    Err(fixme_response_maybe_no_constraints())
-                }
-            }
-        }
-    }
-
-    /// We cannot simply store the result of [EvalCtxt::compute_goal] as we have to deal with
-    /// coinductive cycles.
-    ///
-    /// When we encounter a coinductive cycle, we have to prove the final result of that cycle
-    /// while we are still computing that result. Because of this we continously recompute the
-    /// cycle until the result of the previous iteration is equal to the final result, at which
-    /// point we are done.
-    ///
-    /// This function returns `true` if we were able to finalize the goal and `false` if it has
-    /// updated the provisional cache and we have to recompute the current goal.
-    ///
-    /// FIXME: Refer to the rustc-dev-guide entry once it exists.
-    pub(super) fn try_finalize_goal(
-        &mut self,
-        actual_goal: CanonicalGoal<'tcx>,
-        response: QueryResult<'tcx>,
-    ) -> bool {
-        let cache = &mut self.provisional_cache;
-        let StackElem { goal, has_been_used } = cache.stack.pop().unwrap();
-        assert_eq!(goal, actual_goal);
-
-        let provisional_entry = cache.entries.get_mut(&goal).unwrap();
-        // Check whether the current stack entry is the root of a cycle.
-        //
-        // If so, we either move all participants of that cycle to the global cache
-        // or, in case the provisional response used in the cycle is not equal to the
-        // final response, have to recompute the goal after updating the provisional
-        // response to the final response of this iteration.
-        if has_been_used {
-            if provisional_entry.response == response {
-                // We simply drop all entries according to an immutable condition, so
-                // query instability is not a concern here.
-                #[allow(rustc::potential_query_instability)]
-                cache.entries.retain(|goal, entry| match entry.depth.cmp(&cache.stack.len()) {
-                    Ordering::Less => true,
-                    Ordering::Equal => {
-                        Self::try_move_finished_goal_to_global_cache(
-                            self.tcx,
-                            &mut self.overflow_data,
-                            &cache.stack,
-                            // FIXME: these should be `Copy` :(
-                            goal.clone(),
-                            entry.response.clone(),
-                        );
-                        false
-                    }
-                    Ordering::Greater => bug!("entry with greater depth than the current leaf"),
-                });
-
-                true
-            } else {
-                provisional_entry.response = response;
-                cache.stack.push(StackElem { goal, has_been_used: false });
-                false
-            }
-        } else {
-            Self::try_move_finished_goal_to_global_cache(
-                self.tcx,
-                &mut self.overflow_data,
-                &cache.stack,
-                goal,
-                response,
-            );
-            cache.entries.remove(&goal);
-            true
-        }
-    }
-
-    fn try_move_finished_goal_to_global_cache(
-        tcx: TyCtxt<'tcx>,
-        overflow_data: &mut OverflowData,
-        stack: &[StackElem<'tcx>],
-        goal: CanonicalGoal<'tcx>,
-        response: QueryResult<'tcx>,
-    ) {
-        // We move goals to the global cache if we either did not hit an overflow or if it's
-        // the root goal as that will now always hit the same overflow limit.
-        //
-        // NOTE: We cannot move any non-root goals to the global cache even if their final result
-        // isn't impacted by the overflow as that goal still has unstable query dependencies
-        // because it didn't go its full depth.
-        //
-        // FIXME(@lcnr): We could still cache subtrees which are not impacted by overflow though.
-        // Tracking that info correctly isn't trivial, so I haven't implemented it for now.
-        let should_cache_globally = !overflow_data.did_overflow() || stack.is_empty();
-        if should_cache_globally {
-            // FIXME: move the provisional entry to the global cache.
-            let _ = (tcx, goal, response);
-        }
-    }
-}
-
-fn fixme_response_yes_no_constraints<'tcx>() -> QueryResult<'tcx> {
-    unimplemented!()
-}
-
-fn fixme_response_maybe_no_constraints<'tcx>() -> QueryResult<'tcx> {
-    unimplemented!()
-}
index c014d682a9aaabcdb269168dd6e050f4dae2784c..a2c15123b4fbd7cbb7e818c0bf6859f76ee845cb 100644 (file)
@@ -1,16 +1,14 @@
 use std::mem;
 
-use rustc_data_structures::fx::FxHashMap;
-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::{Certainty, EvalCtxt};
+use super::{Certainty, InferCtxtEvalExt};
 
 /// A trait engine using the new trait solver.
 ///
@@ -42,17 +40,12 @@ fn register_predicate_obligation(
         self.obligations.push(obligation);
     }
 
-    fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
-        let errors = self.select_where_possible(infcx);
-        if !errors.is_empty() {
-            return errors;
-        }
-
+    fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
         self.obligations
             .drain(..)
             .map(|obligation| FulfillmentError {
                 obligation: obligation.clone(),
-                code: FulfillmentErrorCode::CodeSelectionError(SelectionError::Unimplemented),
+                code: FulfillmentErrorCode::CodeAmbiguity,
                 root_obligation: obligation,
             })
             .collect()
@@ -62,19 +55,66 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
         let mut errors = Vec::new();
         for i in 0.. {
             if !infcx.tcx.recursion_limit().value_within_limit(i) {
-                unimplemented!("overflow")
+                unimplemented!("overflowed on pending obligations: {:?}", self.obligations);
             }
 
             let mut has_changed = false;
             for obligation in mem::take(&mut self.obligations) {
-                let mut cx = EvalCtxt::new(infcx.tcx);
-                let (changed, certainty) = match cx.evaluate_goal(infcx, obligation.clone().into())
-                {
+                let goal = obligation.clone().into();
+                let (changed, certainty) = match infcx.evaluate_root_goal(goal) {
                     Ok(result) => result,
                     Err(NoSolution) => {
                         errors.push(FulfillmentError {
                             obligation: obligation.clone(),
-                            code: FulfillmentErrorCode::CodeAmbiguity,
+                            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;
@@ -100,7 +140,10 @@ fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
         self.obligations.clone()
     }
 
-    fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
-        unimplemented!("Should be moved out of `TraitEngine`")
+    fn drain_unstalled_obligations(
+        &mut self,
+        _: &InferCtxt<'tcx>,
+    ) -> Vec<PredicateObligation<'tcx>> {
+        unimplemented!()
     }
 }
index 436f4eea6625bcdf45b7b3e66bec6cba9d4bee80..42f597c781d257e0f97506d931d5121b5d5a83fd 100644 (file)
@@ -1,23 +1,35 @@
-use rustc_infer::infer::canonical::CanonicalVarValues;
+use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::InferCtxt;
+use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
 use rustc_infer::traits::query::NoSolution;
-use rustc_middle::ty::Ty;
+use rustc_infer::traits::ObligationCause;
+use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use rustc_middle::ty::{self, Ty, TypeFoldable};
 use rustc_span::DUMMY_SP;
 
-use crate::solve::ExternalConstraints;
-
-use super::{Certainty, QueryResult, Response};
+use super::Goal;
 
 /// Methods used inside of the canonical queries of the solver.
+///
+/// Most notably these do not care about diagnostics information.
+/// If you find this while looking for methods to use outside of the
+/// solver, you may look at the implementation of these method for
+/// help.
 pub(super) trait InferCtxtExt<'tcx> {
     fn next_ty_infer(&self) -> Ty<'tcx>;
+    fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx>;
+
+    fn eq<T: ToTrace<'tcx>>(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        lhs: T,
+        rhs: T,
+    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>;
 
-    fn make_canonical_response(
+    fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>(
         &self,
-        var_values: CanonicalVarValues<'tcx>,
-        certainty: Certainty,
-    ) -> QueryResult<'tcx>;
+        value: ty::Binder<'tcx, T>,
+    ) -> T;
 }
 
 impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
@@ -27,29 +39,40 @@ fn next_ty_infer(&self) -> Ty<'tcx> {
             span: DUMMY_SP,
         })
     }
+    fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> {
+        self.next_const_var(
+            ty,
+            ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span: DUMMY_SP },
+        )
+    }
 
-    fn make_canonical_response(
+    #[instrument(level = "debug", skip(self, param_env), ret)]
+    fn eq<T: ToTrace<'tcx>>(
         &self,
-        var_values: CanonicalVarValues<'tcx>,
-        certainty: Certainty,
-    ) -> QueryResult<'tcx> {
-        let external_constraints = take_external_constraints(self)?;
-
-        Ok(self.canonicalize_response(Response { var_values, external_constraints, certainty }))
+        param_env: ty::ParamEnv<'tcx>,
+        lhs: T,
+        rhs: T,
+    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
+        self.at(&ObligationCause::dummy(), param_env)
+            .define_opaque_types(false)
+            .eq(lhs, rhs)
+            .map(|InferOk { value: (), obligations }| {
+                obligations.into_iter().map(|o| o.into()).collect()
+            })
+            .map_err(|e| {
+                debug!(?e, "failed to equate");
+                NoSolution
+            })
     }
-}
 
-#[instrument(level = "debug", skip(infcx), ret)]
-fn take_external_constraints<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-) -> Result<ExternalConstraints<'tcx>, NoSolution> {
-    let region_obligations = infcx.take_registered_region_obligations();
-    let opaque_types = infcx.take_opaque_types_for_query_response();
-    Ok(ExternalConstraints {
-        // FIXME: Now that's definitely wrong :)
-        //
-        // Should also do the leak check here I think
-        regions: drop(region_obligations),
-        opaque_types,
-    })
+    fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>(
+        &self,
+        value: ty::Binder<'tcx, T>,
+    ) -> T {
+        self.replace_bound_vars_with_fresh_vars(
+            DUMMY_SP,
+            LateBoundRegionConversionTime::HigherRankedType,
+            value,
+        )
+    }
 }
index 7f5e3208f4e7c0fd03dba54521b106c640ac214b..dd16672cc7a0110fe6917dd9d73f45c7cbf925f4 100644 (file)
 // preserves universes and creates a unique var (in the highest universe) for each
 // appearance of a region.
 
-// FIXME: `CanonicalVarValues` should be interned and `Copy`.
-
 // FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented.
 
 use std::mem;
 
-use rustc_infer::infer::canonical::OriginalQueryValues;
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_hir::def_id::DefId;
+use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
+use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse};
+use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::Obligation;
-use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
+use rustc_middle::infer::canonical::Certainty as OldCertainty;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{RegionOutlivesPredicate, ToPredicate, TypeOutlivesPredicate};
+use rustc_middle::ty::{
+    CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, ToPredicate, TypeOutlivesPredicate,
+};
 use rustc_span::DUMMY_SP;
 
-use self::infcx_ext::InferCtxtExt;
+use crate::traits::ObligationCause;
 
 mod assembly;
-mod cache;
 mod fulfill;
 mod infcx_ext;
-mod overflow;
 mod project_goals;
+mod search_graph;
 mod trait_goals;
 
 pub use fulfill::FulfillmentCtxt;
@@ -87,6 +88,8 @@ pub enum Certainty {
 }
 
 impl Certainty {
+    pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
+
     /// When proving multiple goals using **AND**, e.g. nested obligations for an impl,
     /// use this function to unify the certainty of these goals
     pub fn unify_and(self, other: Certainty) -> Certainty {
@@ -119,7 +122,7 @@ pub enum MaybeCause {
 }
 
 /// Additional constraints returned on success.
-#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable)]
+#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable, Default)]
 pub struct ExternalConstraints<'tcx> {
     // FIXME: implement this.
     regions: (),
@@ -136,51 +139,64 @@ pub struct ExternalConstraints<'tcx> {
 /// solver, merge the two responses again.
 pub type QueryResult<'tcx> = Result<CanonicalResponse<'tcx>, NoSolution>;
 
-pub trait TyCtxtExt<'tcx> {
-    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> TyCtxtExt<'tcx> for TyCtxt<'tcx> {
-    fn evaluate_goal(self, goal: CanonicalGoal<'tcx>) -> QueryResult<'tcx> {
-        let mut cx = EvalCtxt::new(self);
-        cx.evaluate_canonical_goal(goal)
+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<'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct EvalCtxt<'a, 'tcx> {
+    infcx: &'a InferCtxt<'tcx>,
+    var_values: CanonicalVarValues<'tcx>,
 
-    provisional_cache: cache::ProvisionalCache<'tcx>,
-    overflow_data: overflow::OverflowData,
+    search_graph: &'a mut search_graph::SearchGraph<'tcx>,
 }
 
-impl<'tcx> EvalCtxt<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> EvalCtxt<'tcx> {
-        EvalCtxt {
-            tcx,
-            provisional_cache: cache::ProvisionalCache::empty(),
-            overflow_data: overflow::OverflowData::new(tcx),
-        }
-    }
-
-    /// Recursively evaluates `goal`, returning whether any inference vars have
-    /// been constrained and the certainty of the result.
-    fn evaluate_goal(
-        &mut self,
-        infcx: &InferCtxt<'tcx>,
-        goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    ) -> Result<(bool, Certainty), NoSolution> {
-        let mut orig_values = OriginalQueryValues::default();
-        let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values);
-        let canonical_response = self.evaluate_canonical_goal(canonical_goal)?;
-        Ok((
-            true, // FIXME: check whether `var_values` are an identity substitution.
-            fixme_instantiate_canonical_query_response(infcx, &orig_values, canonical_response),
-        ))
+impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
     }
 
-    fn evaluate_canonical_goal(&mut self, goal: CanonicalGoal<'tcx>) -> QueryResult<'tcx> {
-        match self.try_push_stack(goal) {
+    /// The entry point of the solver.
+    ///
+    /// This function deals with (coinductive) cycles, overflow, and caching
+    /// and then calls [`EvalCtxt::compute_goal`] which contains the actual
+    /// logic of the solver.
+    ///
+    /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal]
+    /// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're
+    /// outside of it.
+    #[instrument(level = "debug", skip(tcx, search_graph), ret)]
+    fn evaluate_canonical_goal(
+        tcx: TyCtxt<'tcx>,
+        search_graph: &'a mut search_graph::SearchGraph<'tcx>,
+        canonical_goal: CanonicalGoal<'tcx>,
+    ) -> QueryResult<'tcx> {
+        match search_graph.try_push_stack(tcx, canonical_goal) {
             Ok(()) => {}
             // Our goal is already on the stack, eager return.
             Err(response) => return response,
@@ -191,87 +207,196 @@ fn evaluate_canonical_goal(&mut self, goal: CanonicalGoal<'tcx>) -> QueryResult<
         //
         // FIXME: Similar to `evaluate_all`, this has to check for overflow.
         loop {
-            let result = self.compute_goal(goal);
+            let (ref infcx, goal, var_values) =
+                tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
+            let mut ecx = EvalCtxt { infcx, var_values, search_graph };
+            let result = ecx.compute_goal(goal);
 
             // FIXME: `Response` should be `Copy`
-            if self.try_finalize_goal(goal, result.clone()) {
+            if search_graph.try_finalize_goal(tcx, canonical_goal, result.clone()) {
                 return result;
             }
         }
     }
 
-    fn compute_goal(&mut self, canonical_goal: CanonicalGoal<'tcx>) -> QueryResult<'tcx> {
-        // WARNING: We're looking at a canonical value without instantiating it here.
-        //
-        // We have to be incredibly careful to not change the order of bound variables or
-        // remove any. As we go from `Goal<'tcx, Predicate>` to `Goal` with the variants
-        // of `PredicateKind` this is the case and it is and faster than instantiating and
-        // recanonicalizing.
-        let Goal { param_env, predicate } = canonical_goal.value;
-        if let Some(kind) = predicate.kind().no_bound_vars() {
+    fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> {
+        let external_constraints = take_external_constraints(self.infcx)?;
+
+        Ok(self.infcx.canonicalize_response(Response {
+            var_values: self.var_values,
+            external_constraints,
+            certainty,
+        }))
+    }
+
+    /// Recursively evaluates `goal`, returning whether any inference vars have
+    /// been constrained and the certainty of the result.
+    fn evaluate_goal(
+        &mut self,
+        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+    ) -> Result<(bool, Certainty), NoSolution> {
+        let mut orig_values = OriginalQueryValues::default();
+        let canonical_goal = self.infcx.canonicalize_query(goal, &mut orig_values);
+        let canonical_response =
+            EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
+        Ok((
+            !canonical_response.value.var_values.is_identity(),
+            instantiate_canonical_query_response(self.infcx, &orig_values, canonical_response),
+        ))
+    }
+
+    fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
+        let Goal { param_env, predicate } = goal;
+        let kind = predicate.kind();
+        if let Some(kind) = kind.no_bound_vars() {
             match kind {
-                ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => self.compute_trait_goal(
-                    canonical_goal.unchecked_rebind(Goal { param_env, predicate }),
-                ),
-                ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => self
-                    .compute_projection_goal(
-                        canonical_goal.unchecked_rebind(Goal { param_env, predicate }),
-                    ),
-                ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => self
-                    .compute_type_outlives_goal(
-                        canonical_goal.unchecked_rebind(Goal { param_env, predicate }),
-                    ),
-                ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => self
-                    .compute_region_outlives_goal(
-                        canonical_goal.unchecked_rebind(Goal { param_env, predicate }),
-                    ),
+                ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => {
+                    self.compute_trait_goal(Goal { param_env, predicate })
+                }
+                ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => {
+                    self.compute_projection_goal(Goal { param_env, predicate })
+                }
+                ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => {
+                    self.compute_type_outlives_goal(Goal { param_env, predicate })
+                }
+                ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => {
+                    self.compute_region_outlives_goal(Goal { param_env, predicate })
+                }
+                ty::PredicateKind::Subtype(predicate) => {
+                    self.compute_subtype_goal(Goal { param_env, predicate })
+                }
+                ty::PredicateKind::Coerce(predicate) => {
+                    self.compute_coerce_goal(Goal { param_env, predicate })
+                }
+                ty::PredicateKind::ClosureKind(def_id, substs, kind) => self
+                    .compute_closure_kind_goal(Goal {
+                        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::ClosureKind(_, _, _)
-                | ty::PredicateKind::Subtype(_)
-                | ty::PredicateKind::Coerce(_)
-                | ty::PredicateKind::ConstEvaluatable(_)
-                | ty::PredicateKind::ConstEquate(_, _)
-                | ty::PredicateKind::TypeWellFormedFromEnv(_)
-                | ty::PredicateKind::Ambiguous => unimplemented!(),
+                ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => {
+                    self.make_canonical_response(Certainty::Yes)
+                }
+                ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+                    bug!("TypeWellFormedFromEnv is only used for Chalk")
+                }
             }
         } else {
-            let (infcx, goal, var_values) =
-                self.tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
-            let kind = infcx.replace_bound_vars_with_placeholders(goal.predicate.kind());
-            let goal = goal.with(self.tcx, ty::Binder::dummy(kind));
-            let (_, certainty) = self.evaluate_goal(&infcx, goal)?;
-            infcx.make_canonical_response(var_values, certainty)
+            let kind = self.infcx.replace_bound_vars_with_placeholders(kind);
+            let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
+            let (_, certainty) = self.evaluate_goal(goal)?;
+            self.make_canonical_response(certainty)
         }
     }
 
     fn compute_type_outlives_goal(
         &mut self,
-        _goal: CanonicalGoal<'tcx, TypeOutlivesPredicate<'tcx>>,
+        _goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>,
     ) -> QueryResult<'tcx> {
-        todo!()
+        self.make_canonical_response(Certainty::Yes)
     }
 
     fn compute_region_outlives_goal(
         &mut self,
-        _goal: CanonicalGoal<'tcx, RegionOutlivesPredicate<'tcx>>,
+        _goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>,
+    ) -> QueryResult<'tcx> {
+        self.make_canonical_response(Certainty::Yes)
+    }
+
+    fn compute_coerce_goal(
+        &mut self,
+        goal: Goal<'tcx, CoercePredicate<'tcx>>,
+    ) -> QueryResult<'tcx> {
+        self.compute_subtype_goal(Goal {
+            param_env: goal.param_env,
+            predicate: SubtypePredicate {
+                a_is_expected: false,
+                a: goal.predicate.a,
+                b: goal.predicate.b,
+            },
+        })
+    }
+
+    fn compute_subtype_goal(
+        &mut self,
+        goal: Goal<'tcx, SubtypePredicate<'tcx>>,
+    ) -> QueryResult<'tcx> {
+        if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() {
+            // FIXME: Do we want to register a subtype relation between these vars?
+            // That won't actually reflect in the query response, so it seems moot.
+            self.make_canonical_response(Certainty::AMBIGUOUS)
+        } else {
+            let InferOk { value: (), obligations } = self
+                .infcx
+                .at(&ObligationCause::dummy(), goal.param_env)
+                .sub(goal.predicate.a, goal.predicate.b)?;
+            self.evaluate_all_and_make_canonical_response(
+                obligations.into_iter().map(|pred| pred.into()).collect(),
+            )
+        }
+    }
+
+    fn compute_closure_kind_goal(
+        &mut self,
+        goal: Goal<'tcx, (DefId, ty::SubstsRef<'tcx>, ty::ClosureKind)>,
     ) -> QueryResult<'tcx> {
-        todo!()
+        let (_, substs, expected_kind) = goal.predicate;
+        let found_kind = substs.as_closure().kind_ty().to_opt_closure_kind();
+
+        let Some(found_kind) = found_kind else {
+            return self.make_canonical_response(Certainty::AMBIGUOUS);
+        };
+        if found_kind.extends(expected_kind) {
+            self.make_canonical_response(Certainty::Yes)
+        } else {
+            Err(NoSolution)
+        }
+    }
+
+    fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> {
+        if self.tcx().check_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> {
+        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> {
+impl<'tcx> EvalCtxt<'_, 'tcx> {
+    // Recursively evaluates a list of goals to completion, returning the certainty
+    // of all of the goals.
     fn evaluate_all(
         &mut self,
-        infcx: &InferCtxt<'tcx>,
         mut goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
     ) -> Result<Certainty, NoSolution> {
         let mut new_goals = Vec::new();
         self.repeat_while_none(|this| {
             let mut has_changed = Err(Certainty::Yes);
             for goal in goals.drain(..) {
-                let (changed, certainty) = match this.evaluate_goal(infcx, goal) {
+                let (changed, certainty) = match this.evaluate_goal(goal) {
                     Ok(result) => result,
                     Err(NoSolution) => return Some(Err(NoSolution)),
                 };
@@ -298,12 +423,71 @@ fn evaluate_all(
             }
         })
     }
+
+    // Recursively evaluates a list of goals to completion, making a query response.
+    //
+    // This is just a convenient way of calling [`EvalCtxt::evaluate_all`],
+    // then [`EvalCtxt::make_canonical_response`].
+    fn evaluate_all_and_make_canonical_response(
+        &mut self,
+        goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
+    ) -> QueryResult<'tcx> {
+        self.evaluate_all(goals).and_then(|certainty| self.make_canonical_response(certainty))
+    }
+}
+
+#[instrument(level = "debug", skip(infcx), ret)]
+fn take_external_constraints<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+) -> Result<ExternalConstraints<'tcx>, NoSolution> {
+    let region_obligations = infcx.take_registered_region_obligations();
+    let opaque_types = infcx.take_opaque_types_for_query_response();
+    Ok(ExternalConstraints {
+        // FIXME: Now that's definitely wrong :)
+        //
+        // Should also do the leak check here I think
+        regions: drop(region_obligations),
+        opaque_types,
+    })
 }
 
-fn fixme_instantiate_canonical_query_response<'tcx>(
-    _: &InferCtxt<'tcx>,
-    _: &OriginalQueryValues<'tcx>,
-    _: CanonicalResponse<'tcx>,
+fn instantiate_canonical_query_response<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    original_values: &OriginalQueryValues<'tcx>,
+    response: CanonicalResponse<'tcx>,
 ) -> Certainty {
-    unimplemented!()
+    let Ok(InferOk { value, obligations }) = infcx
+        .instantiate_query_response_and_region_obligations(
+            &ObligationCause::dummy(),
+            ty::ParamEnv::empty(),
+            original_values,
+            &response.unchecked_map(|resp| QueryResponse {
+                var_values: resp.var_values,
+                region_constraints: QueryRegionConstraints::default(),
+                certainty: match resp.certainty {
+                    Certainty::Yes => OldCertainty::Proven,
+                    Certainty::Maybe(_) => OldCertainty::Ambiguous,
+                },
+                opaque_types: resp.external_constraints.opaque_types,
+                value: resp.certainty,
+            }),
+        ) else { bug!(); };
+    assert!(obligations.is_empty());
+    value
+}
+
+pub(super) fn response_no_constraints<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    goal: Canonical<'tcx, impl Sized>,
+    certainty: Certainty,
+) -> QueryResult<'tcx> {
+    Ok(Canonical {
+        max_universe: goal.max_universe,
+        variables: goal.variables,
+        value: Response {
+            var_values: CanonicalVarValues::make_identity(tcx, goal.variables),
+            external_constraints: Default::default(),
+            certainty,
+        },
+    })
 }
diff --git a/compiler/rustc_trait_selection/src/solve/overflow.rs b/compiler/rustc_trait_selection/src/solve/overflow.rs
deleted file mode 100644 (file)
index fdd6adb..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-use rustc_infer::traits::query::NoSolution;
-use rustc_middle::ty::TyCtxt;
-use rustc_session::Limit;
-
-use super::{Certainty, EvalCtxt, MaybeCause, QueryResult};
-
-/// When detecting a solver overflow, we return ambiguity. Overflow can be
-/// *hidden* by either a fatal error in an **AND** or a trivial success in an **OR**.
-///
-/// This is in issue in case of exponential blowup, e.g. if each goal on the stack
-/// has multiple nested (overflowing) candidates. To deal with this, we reduce the limit
-/// used by the solver when hitting the default limit for the first time.
-///
-/// FIXME: Get tests where always using the `default_limit` results in a hang and refer
-/// to them here. We can also improve the overflow strategy if necessary.
-pub(super) struct OverflowData {
-    default_limit: Limit,
-    current_limit: Limit,
-    /// When proving an **AND** we have to repeatedly iterate over the yet unproven goals.
-    ///
-    /// Because of this each iteration also increases the depth in addition to the stack
-    /// depth.
-    additional_depth: usize,
-}
-
-impl OverflowData {
-    pub(super) fn new(tcx: TyCtxt<'_>) -> OverflowData {
-        let default_limit = tcx.recursion_limit();
-        OverflowData { default_limit, current_limit: default_limit, additional_depth: 0 }
-    }
-
-    #[inline]
-    pub(super) fn did_overflow(&self) -> bool {
-        self.default_limit.0 != self.current_limit.0
-    }
-
-    #[inline]
-    pub(super) fn has_overflow(&self, depth: usize) -> bool {
-        !self.current_limit.value_within_limit(depth + self.additional_depth)
-    }
-
-    /// Updating the current limit when hitting overflow.
-    fn deal_with_overflow(&mut self) {
-        // When first hitting overflow we reduce the overflow limit
-        // for all future goals to prevent hangs if there's an exponental
-        // blowup.
-        self.current_limit.0 = self.default_limit.0 / 8;
-    }
-}
-
-impl<'tcx> EvalCtxt<'tcx> {
-    pub(super) fn deal_with_overflow(&mut self) -> QueryResult<'tcx> {
-        self.overflow_data.deal_with_overflow();
-        fixme_response_overflow_no_constraints()
-    }
-
-    /// A `while`-loop which tracks overflow.
-    pub(super) fn repeat_while_none(
-        &mut self,
-        mut loop_body: impl FnMut(&mut Self) -> Option<Result<Certainty, NoSolution>>,
-    ) -> Result<Certainty, NoSolution> {
-        let start_depth = self.overflow_data.additional_depth;
-        let depth = self.provisional_cache.current_depth();
-        while !self.overflow_data.has_overflow(depth) {
-            if let Some(result) = loop_body(self) {
-                self.overflow_data.additional_depth = start_depth;
-                return result;
-            }
-
-            self.overflow_data.additional_depth += 1;
-        }
-        self.overflow_data.additional_depth = start_depth;
-        self.overflow_data.deal_with_overflow();
-        Ok(Certainty::Maybe(MaybeCause::Overflow))
-    }
-}
-
-fn fixme_response_overflow_no_constraints<'tcx>() -> QueryResult<'tcx> {
-    unimplemented!()
-}
index 3d649bea19ddfc966ed0f9ceb3e659e12f4a0950..b175a6dde179f1378ab0570c69607a5bbce246df 100644 (file)
 use crate::traits::{specialization_graph, translate_substs};
 
-use super::assembly::{self, AssemblyCtxt};
-use super::{CanonicalGoal, EvalCtxt, Goal, QueryResult};
+use super::assembly::{self, Candidate, CandidateSource};
+use super::infcx_ext::InferCtxtExt;
+use super::trait_goals::structural_traits;
+use super::{Certainty, EvalCtxt, Goal, QueryResult};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_hir::LangItem;
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::specialization_graph::LeafDef;
-use rustc_infer::traits::{ObligationCause, Reveal};
+use rustc_infer::traits::Reveal;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
-use rustc_middle::ty::ProjectionPredicate;
-use rustc_middle::ty::TypeVisitable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::DUMMY_SP;
+use rustc_middle::ty::{ProjectionPredicate, TypeSuperVisitable, TypeVisitor};
+use rustc_middle::ty::{ToPredicate, TypeVisitable};
+use rustc_span::{sym, DUMMY_SP};
 use std::iter;
+use std::ops::ControlFlow;
 
-#[allow(dead_code)] // FIXME: implement and use all variants.
-#[derive(Debug, Clone, Copy)]
-pub(super) enum CandidateSource {
-    Impl(DefId),
-    ParamEnv(usize),
-    Builtin,
-}
-
-type Candidate<'tcx> = assembly::Candidate<'tcx, ProjectionPredicate<'tcx>>;
-
-impl<'tcx> EvalCtxt<'tcx> {
+impl<'tcx> EvalCtxt<'_, 'tcx> {
     pub(super) fn compute_projection_goal(
         &mut self,
-        goal: CanonicalGoal<'tcx, ProjectionPredicate<'tcx>>,
+        goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
     ) -> QueryResult<'tcx> {
-        let candidates = AssemblyCtxt::assemble_and_evaluate_candidates(self, goal);
-        self.merge_project_candidates(candidates)
+        // To only compute normalization once for each projection we only
+        // normalize if the expected term is an unconstrained inference variable.
+        //
+        // E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
+        // `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
+        // `U` and equate it with `u32`. This means that we don't need a separate
+        // projection cache in the solver.
+        if self.term_is_fully_unconstrained(goal) {
+            let candidates = self.assemble_and_evaluate_candidates(goal);
+            self.merge_project_candidates(candidates)
+        } else {
+            let predicate = goal.predicate;
+            let unconstrained_rhs = match predicate.term.unpack() {
+                ty::TermKind::Ty(_) => self.infcx.next_ty_infer().into(),
+                ty::TermKind::Const(ct) => self.infcx.next_const_infer(ct.ty()).into(),
+            };
+            let unconstrained_predicate = ty::Clause::Projection(ProjectionPredicate {
+                projection_ty: goal.predicate.projection_ty,
+                term: unconstrained_rhs,
+            });
+            let (_has_changed, normalize_certainty) =
+                self.evaluate_goal(goal.with(self.tcx(), unconstrained_predicate))?;
+
+            let nested_eq_goals =
+                self.infcx.eq(goal.param_env, unconstrained_rhs, predicate.term)?;
+            let eval_certainty = self.evaluate_all(nested_eq_goals)?;
+            self.make_canonical_response(normalize_certainty.unify_and(eval_certainty))
+        }
+    }
+
+    /// Is the projection predicate is of the form `exists<T> <Ty as Trait>::Assoc = T`.
+    ///
+    /// This is the case if the `term` is an inference variable in the innermost universe
+    /// and does not occur in any other part of the predicate.
+    fn term_is_fully_unconstrained(&self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>) -> bool {
+        let infcx = self.infcx;
+        let term_is_infer = match goal.predicate.term.unpack() {
+            ty::TermKind::Ty(ty) => {
+                if let &ty::Infer(ty::TyVar(vid)) = ty.kind() {
+                    match infcx.probe_ty_var(vid) {
+                        Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"),
+                        Err(universe) => universe == infcx.universe(),
+                    }
+                } else {
+                    false
+                }
+            }
+            ty::TermKind::Const(ct) => {
+                if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
+                    match self.infcx.probe_const_var(vid) {
+                        Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"),
+                        Err(universe) => universe == infcx.universe(),
+                    }
+                } else {
+                    false
+                }
+            }
+        };
+
+        // Guard against `<T as Trait<?0>>::Assoc = ?0>`.
+        struct ContainsTerm<'tcx> {
+            term: ty::Term<'tcx>,
+        }
+        impl<'tcx> TypeVisitor<'tcx> for ContainsTerm<'tcx> {
+            type BreakTy = ();
+            fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+                if t.needs_infer() {
+                    if ty::Term::from(t) == self.term {
+                        ControlFlow::Break(())
+                    } else {
+                        t.super_visit_with(self)
+                    }
+                } else {
+                    ControlFlow::Continue(())
+                }
+            }
+
+            fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+                if c.needs_infer() {
+                    if ty::Term::from(c) == self.term {
+                        ControlFlow::Break(())
+                    } else {
+                        c.super_visit_with(self)
+                    }
+                } else {
+                    ControlFlow::Continue(())
+                }
+            }
+        }
+
+        let mut visitor = ContainsTerm { term: goal.predicate.term };
+
+        term_is_infer
+            && goal.predicate.projection_ty.visit_with(&mut visitor).is_continue()
+            && goal.param_env.visit_with(&mut visitor).is_continue()
     }
 
     fn merge_project_candidates(
@@ -83,14 +170,13 @@ fn project_candidate_should_be_dropped_in_favor_of(
         match (candidate.source, other.source) {
             (CandidateSource::Impl(_), _)
             | (CandidateSource::ParamEnv(_), _)
-            | (CandidateSource::Builtin, _) => unimplemented!(),
+            | (CandidateSource::BuiltinImpl, _)
+            | (CandidateSource::AliasBound, _) => unimplemented!(),
         }
     }
 }
 
 impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
-    type CandidateSource = CandidateSource;
-
     fn self_ty(self) -> Ty<'tcx> {
         self.self_ty()
     }
@@ -104,33 +190,26 @@ fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
     }
 
     fn consider_impl_candidate(
-        acx: &mut AssemblyCtxt<'_, 'tcx, ProjectionPredicate<'tcx>>,
+        ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
         impl_def_id: DefId,
-    ) {
-        let tcx = acx.cx.tcx;
+    ) -> QueryResult<'tcx> {
+        let tcx = ecx.tcx();
+
         let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
-        let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap();
+        let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
         let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
         if iter::zip(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs)
             .any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
         {
-            return;
+            return Err(NoSolution);
         }
 
-        acx.infcx.probe(|_| {
-            let impl_substs = acx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
+        ecx.infcx.probe(|_| {
+            let impl_substs = ecx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
             let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
 
-            let Ok(InferOk { obligations, .. }) = acx
-                .infcx
-                .at(&ObligationCause::dummy(), goal.param_env)
-                .define_opaque_types(false)
-                .eq(goal_trait_ref, impl_trait_ref)
-                .map_err(|e| debug!("failed to equate trait refs: {e:?}"))
-            else {
-                return
-            };
+            let mut nested_goals = ecx.infcx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
             let where_clause_bounds = tcx
                 .predicates_of(impl_def_id)
                 .instantiate(tcx, impl_substs)
@@ -138,17 +217,20 @@ fn consider_impl_candidate(
                 .into_iter()
                 .map(|pred| goal.with(tcx, pred));
 
-            let nested_goals = obligations.into_iter().map(|o| o.into()).chain(where_clause_bounds).collect();
-            let Ok(trait_ref_certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return };
+            nested_goals.extend(where_clause_bounds);
+            let trait_ref_certainty = ecx.evaluate_all(nested_goals)?;
 
+            // In case the associated item is hidden due to specialization, we have to
+            // return ambiguity this would otherwise be incomplete, resulting in
+            // unsoundness during coherence (#105782).
             let Some(assoc_def) = fetch_eligible_assoc_item_def(
-                acx.infcx,
+                ecx.infcx,
                 goal.param_env,
                 goal_trait_ref,
                 goal.predicate.def_id(),
                 impl_def_id
-            ) else {
-                return
+            )? else {
+                return ecx.make_canonical_response(trait_ref_certainty.unify_and(Certainty::AMBIGUOUS));
             };
 
             if !assoc_def.item.defaultness(tcx).has_value() {
@@ -171,10 +253,10 @@ fn consider_impl_candidate(
             let impl_substs_with_gat = goal.predicate.projection_ty.substs.rebase_onto(
                 tcx,
                 goal_trait_ref.def_id,
-                impl_trait_ref.substs,
+                impl_substs,
             );
             let substs = translate_substs(
-                acx.infcx,
+                ecx.infcx,
                 goal.param_env,
                 impl_def_id,
                 impl_substs_with_gat,
@@ -185,7 +267,8 @@ fn consider_impl_candidate(
             let is_const = matches!(tcx.def_kind(assoc_def.item.def_id), DefKind::AssocConst);
             let ty = tcx.bound_type_of(assoc_def.item.def_id);
             let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
-                let identity_substs = ty::InternalSubsts::identity_for_item(tcx, assoc_def.item.def_id);
+                let identity_substs =
+                    ty::InternalSubsts::identity_for_item(tcx, assoc_def.item.def_id);
                 let did = ty::WithOptConstParam::unknown(assoc_def.item.def_id);
                 let kind =
                     ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs));
@@ -194,23 +277,283 @@ fn consider_impl_candidate(
                 ty.map_bound(|ty| ty.into())
             };
 
-            let Ok(InferOk { obligations, .. }) = acx
+            // The term of our goal should be fully unconstrained, so this should never fail.
+            //
+            // It can however be ambiguous when the resolved type is a projection.
+            let nested_goals = ecx
                 .infcx
-                .at(&ObligationCause::dummy(), goal.param_env)
-                .define_opaque_types(false)
-                .eq(goal.predicate.term,  term.subst(tcx, substs))
-                .map_err(|e| debug!("failed to equate trait refs: {e:?}"))
-            else {
-                return
-            };
+                .eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs))
+                .expect("failed to unify with unconstrained term");
+            let rhs_certainty =
+                ecx.evaluate_all(nested_goals).expect("failed to unify with unconstrained term");
+
+            ecx.make_canonical_response(trait_ref_certainty.unify_and(rhs_certainty))
+        })
+    }
+
+    fn consider_assumption(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        assumption: ty::Predicate<'tcx>,
+    ) -> QueryResult<'tcx> {
+        if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
+            && poly_projection_pred.projection_def_id() == goal.predicate.def_id()
+        {
+            ecx.infcx.probe(|_| {
+                let assumption_projection_pred =
+                    ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred);
+                let nested_goals = ecx.infcx.eq(
+                    goal.param_env,
+                    goal.predicate.projection_ty,
+                    assumption_projection_pred.projection_ty,
+                )?;
+                let subst_certainty = ecx.evaluate_all(nested_goals)?;
+
+                // The term of our goal should be fully unconstrained, so this should never fail.
+                //
+                // It can however be ambiguous when the resolved type is a projection.
+                let nested_goals = ecx
+                    .infcx
+                    .eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
+                    .expect("failed to unify with unconstrained term");
+                let rhs_certainty = ecx
+                    .evaluate_all(nested_goals)
+                    .expect("failed to unify with unconstrained term");
+
+                ecx.make_canonical_response(subst_certainty.unify_and(rhs_certainty))
+            })
+        } else {
+            Err(NoSolution)
+        }
+    }
+
+    fn consider_auto_trait_candidate(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        bug!("auto traits do not have associated types: {:?}", goal);
+    }
+
+    fn consider_trait_alias_candidate(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        bug!("trait aliases do not have associated types: {:?}", goal);
+    }
+
+    fn consider_builtin_sized_candidate(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        bug!("`Sized` does not have an associated type: {:?}", goal);
+    }
+
+    fn consider_builtin_copy_clone_candidate(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
+    }
+
+    fn consider_builtin_pointer_sized_candidate(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        bug!("`PointerSized` does not have an associated type: {:?}", goal);
+    }
+
+    fn consider_builtin_fn_trait_candidates(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        goal_kind: ty::ClosureKind,
+    ) -> QueryResult<'tcx> {
+        if let Some(tupled_inputs_and_output) =
+            structural_traits::extract_tupled_inputs_and_output_from_callable(
+                ecx.tcx(),
+                goal.predicate.self_ty(),
+                goal_kind,
+            )?
+        {
+            let pred = tupled_inputs_and_output
+                .map_bound(|(inputs, output)| ty::ProjectionPredicate {
+                    projection_ty: ecx
+                        .tcx()
+                        .mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]),
+                    term: output.into(),
+                })
+                .to_predicate(ecx.tcx());
+            Self::consider_assumption(ecx, goal, pred)
+        } else {
+            ecx.make_canonical_response(Certainty::AMBIGUOUS)
+        }
+    }
+
+    fn consider_builtin_tuple_candidate(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> 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::GeneratorWitnessMIR(..)
+                | 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 nested_goals = obligations.into_iter().map(|o| o.into()).collect();
-            let Ok(rhs_certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return };
+                    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));
 
-            let certainty = trait_ref_certainty.unify_and(rhs_certainty);
-            acx.try_insert_candidate(CandidateSource::Impl(impl_def_id), certainty);
+                    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.
@@ -224,10 +567,9 @@ fn fetch_eligible_assoc_item_def<'tcx>(
     goal_trait_ref: ty::TraitRef<'tcx>,
     trait_assoc_def_id: DefId,
     impl_def_id: DefId,
-) -> Option<LeafDef> {
+) -> Result<Option<LeafDef>, NoSolution> {
     let node_item = specialization_graph::assoc_def(infcx.tcx, impl_def_id, trait_assoc_def_id)
-        .map_err(|ErrorGuaranteed { .. }| ())
-        .ok()?;
+        .map_err(|ErrorGuaranteed { .. }| NoSolution)?;
 
     let eligible = if node_item.is_final() {
         // Non-specializable items are always projectable.
@@ -246,5 +588,5 @@ fn fetch_eligible_assoc_item_def<'tcx>(
         }
     };
 
-    if eligible { Some(node_item) } else { None }
+    if eligible { Ok(Some(node_item)) } else { Ok(None) }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs
new file mode 100644 (file)
index 0000000..80a388b
--- /dev/null
@@ -0,0 +1,124 @@
+//! This module both handles the global cache which stores "finished" goals,
+//! and the provisional cache which contains partially computed goals.
+//!
+//! The provisional cache is necessary when dealing with coinductive cycles.
+//!
+//! For more information about the provisional cache and coinduction in general,
+//! check out the relevant section of the rustc-dev-guide.
+//!
+//! FIXME(@lcnr): Write that section, feel free to ping me if you need help here
+//! before then or if I still haven't done that before January 2023.
+use super::overflow::OverflowData;
+use super::StackDepth;
+use crate::solve::{CanonicalGoal, QueryResult};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_index::vec::IndexVec;
+use rustc_middle::ty::TyCtxt;
+
+rustc_index::newtype_index! {
+    pub struct EntryIndex {}
+}
+
+#[derive(Debug, Clone)]
+pub(super) struct ProvisionalEntry<'tcx> {
+    // In case we have a coinductive cycle, this is the
+    // the currently least restrictive result of this goal.
+    pub(super) response: QueryResult<'tcx>,
+    // In case of a cycle, the position of deepest stack entry involved
+    // in that cycle. This is monotonically decreasing in the stack as all
+    // elements between the current stack element in the deepest stack entry
+    // involved have to also be involved in that cycle.
+    //
+    // We can only move entries to the global cache once we're complete done
+    // with the cycle. If this entry has not been involved in a cycle,
+    // this is just its own depth.
+    pub(super) depth: StackDepth,
+
+    // The goal for this entry. Should always be equal to the corresponding goal
+    // in the lookup table.
+    pub(super) goal: CanonicalGoal<'tcx>,
+}
+
+pub(super) struct ProvisionalCache<'tcx> {
+    pub(super) entries: IndexVec<EntryIndex, ProvisionalEntry<'tcx>>,
+    // FIXME: This is only used to quickly check whether a given goal
+    // is in the cache. We should experiment with using something like
+    // `SsoHashSet` here because in most cases there are only a few entries.
+    pub(super) lookup_table: FxHashMap<CanonicalGoal<'tcx>, EntryIndex>,
+}
+
+impl<'tcx> ProvisionalCache<'tcx> {
+    pub(super) fn empty() -> ProvisionalCache<'tcx> {
+        ProvisionalCache { entries: Default::default(), lookup_table: Default::default() }
+    }
+
+    pub(super) fn is_empty(&self) -> bool {
+        self.entries.is_empty() && self.lookup_table.is_empty()
+    }
+
+    /// Adds a dependency from the current leaf to `target` in the cache
+    /// to prevent us from moving any goals which depend on the current leaf
+    /// to the global cache while we're still computing `target`.
+    ///
+    /// Its important to note that `target` may already be part of a different cycle.
+    /// In this case we have to ensure that we also depend on all other goals
+    /// in the existing cycle in addition to the potentially direct cycle with `target`.
+    pub(super) fn add_dependency_of_leaf_on(&mut self, target: EntryIndex) {
+        let depth = self.entries[target].depth;
+        for provisional_entry in &mut self.entries.raw[target.index()..] {
+            // The depth of `target` is the position of the deepest goal in the stack
+            // on which `target` depends. That goal is the `root` of this cycle.
+            //
+            // Any entry which was added after `target` is either on the stack itself
+            // at which point its depth is definitely at least as high as the depth of
+            // `root`. If it's not on the stack itself it has to depend on a goal
+            // between `root` and `leaf`. If it were to depend on a goal deeper in the
+            // stack than `root`, then `root` would also depend on that goal, at which
+            // point `root` wouldn't be the root anymore.
+            debug_assert!(provisional_entry.depth >= depth);
+            provisional_entry.depth = depth;
+        }
+
+        // We only update entries which were added after `target` as no other
+        // entry should have a higher depth.
+        //
+        // Any entry which previously had a higher depth than target has to
+        // be between `target` and `root`. Because of this we would have updated
+        // its depth when calling `add_dependency_of_leaf_on(root)` for `target`.
+        if cfg!(debug_assertions) {
+            self.entries.iter().all(|e| e.depth <= depth);
+        }
+    }
+
+    pub(super) fn depth(&self, entry_index: EntryIndex) -> StackDepth {
+        self.entries[entry_index].depth
+    }
+
+    pub(super) fn provisional_result(&self, entry_index: EntryIndex) -> QueryResult<'tcx> {
+        // FIXME: Responses should probably be `Copy` as well
+        self.entries[entry_index].response.clone()
+    }
+}
+
+pub(super) fn try_move_finished_goal_to_global_cache<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    overflow_data: &mut OverflowData,
+    stack: &IndexVec<super::StackDepth, super::StackElem<'tcx>>,
+    goal: CanonicalGoal<'tcx>,
+    response: QueryResult<'tcx>,
+) {
+    // We move goals to the global cache if we either did not hit an overflow or if it's
+    // the root goal as that will now always hit the same overflow limit.
+    //
+    // NOTE: We cannot move any non-root goals to the global cache even if their final result
+    // isn't impacted by the overflow as that goal still has unstable query dependencies
+    // because it didn't go its full depth.
+    //
+    // FIXME(@lcnr): We could still cache subtrees which are not impacted by overflow though.
+    // Tracking that info correctly isn't trivial, so I haven't implemented it for now.
+    let should_cache_globally = !overflow_data.did_overflow() || stack.is_empty();
+    if should_cache_globally {
+        // FIXME: move the provisional entry to the global cache.
+        let _ = (tcx, goal, response);
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
new file mode 100644 (file)
index 0000000..0030e9a
--- /dev/null
@@ -0,0 +1,178 @@
+mod cache;
+mod overflow;
+
+use self::cache::ProvisionalEntry;
+use super::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
+use cache::ProvisionalCache;
+use overflow::OverflowData;
+use rustc_index::vec::IndexVec;
+use rustc_middle::ty::TyCtxt;
+use std::collections::hash_map::Entry;
+
+rustc_index::newtype_index! {
+    pub struct StackDepth {}
+}
+
+struct StackElem<'tcx> {
+    goal: CanonicalGoal<'tcx>,
+    has_been_used: bool,
+}
+
+pub(super) struct SearchGraph<'tcx> {
+    /// The stack of goals currently being computed.
+    ///
+    /// An element is *deeper* in the stack if its index is *lower*.
+    stack: IndexVec<StackDepth, StackElem<'tcx>>,
+    overflow_data: OverflowData,
+    provisional_cache: ProvisionalCache<'tcx>,
+}
+
+impl<'tcx> SearchGraph<'tcx> {
+    pub(super) fn new(tcx: TyCtxt<'tcx>) -> SearchGraph<'tcx> {
+        Self {
+            stack: Default::default(),
+            overflow_data: OverflowData::new(tcx),
+            provisional_cache: ProvisionalCache::empty(),
+        }
+    }
+
+    pub(super) fn is_empty(&self) -> bool {
+        self.stack.is_empty()
+            && self.provisional_cache.is_empty()
+            && !self.overflow_data.did_overflow()
+    }
+
+    /// Tries putting the new goal on the stack, returning an error if it is already cached.
+    ///
+    /// This correctly updates the provisional cache if there is a cycle.
+    pub(super) fn try_push_stack(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        goal: CanonicalGoal<'tcx>,
+    ) -> Result<(), QueryResult<'tcx>> {
+        // FIXME: start by checking the global cache
+
+        // Look at the provisional cache to check for cycles.
+        let cache = &mut self.provisional_cache;
+        match cache.lookup_table.entry(goal) {
+            // No entry, simply push this goal on the stack after dealing with overflow.
+            Entry::Vacant(v) => {
+                if self.overflow_data.has_overflow(self.stack.len()) {
+                    return Err(self.deal_with_overflow(tcx, goal));
+                }
+
+                let depth = self.stack.push(StackElem { goal, has_been_used: false });
+                let response = super::response_no_constraints(tcx, goal, Certainty::Yes);
+                let entry_index = cache.entries.push(ProvisionalEntry { response, depth, goal });
+                v.insert(entry_index);
+                Ok(())
+            }
+            // We have a nested goal which relies on a goal `root` deeper in the stack.
+            //
+            // We first store that we may have to rerun `evaluate_goal` for `root` in case the
+            // provisional response is not equal to the final response. We also update the depth
+            // of all goals which recursively depend on our current goal to depend on `root`
+            // instead.
+            //
+            // Finally we can return either the provisional response for that goal if we have a
+            // coinductive cycle or an ambiguous result if the cycle is inductive.
+            Entry::Occupied(entry_index) => {
+                let entry_index = *entry_index.get();
+
+                cache.add_dependency_of_leaf_on(entry_index);
+                let stack_depth = cache.depth(entry_index);
+
+                self.stack[stack_depth].has_been_used = true;
+                // NOTE: The goals on the stack aren't the only goals involved in this cycle.
+                // We can also depend on goals which aren't part of the stack but coinductively
+                // depend on the stack themselves. We already checked whether all the goals
+                // between these goals and their root on the stack. This means that as long as
+                // each goal in a cycle is checked for coinductivity by itself, simply checking
+                // the stack is enough.
+                if self.stack.raw[stack_depth.index()..]
+                    .iter()
+                    .all(|g| g.goal.value.predicate.is_coinductive(tcx))
+                {
+                    Err(cache.provisional_result(entry_index))
+                } else {
+                    Err(super::response_no_constraints(
+                        tcx,
+                        goal,
+                        Certainty::Maybe(MaybeCause::Overflow),
+                    ))
+                }
+            }
+        }
+    }
+
+    /// We cannot simply store the result of [super::EvalCtxt::compute_goal] as we have to deal with
+    /// coinductive cycles.
+    ///
+    /// When we encounter a coinductive cycle, we have to prove the final result of that cycle
+    /// while we are still computing that result. Because of this we continously recompute the
+    /// cycle until the result of the previous iteration is equal to the final result, at which
+    /// point we are done.
+    ///
+    /// This function returns `true` if we were able to finalize the goal and `false` if it has
+    /// updated the provisional cache and we have to recompute the current goal.
+    ///
+    /// FIXME: Refer to the rustc-dev-guide entry once it exists.
+    pub(super) fn try_finalize_goal(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        actual_goal: CanonicalGoal<'tcx>,
+        response: QueryResult<'tcx>,
+    ) -> bool {
+        let StackElem { goal, has_been_used } = self.stack.pop().unwrap();
+        assert_eq!(goal, actual_goal);
+
+        let cache = &mut self.provisional_cache;
+        let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap();
+        let provisional_entry = &mut cache.entries[provisional_entry_index];
+        let depth = provisional_entry.depth;
+        // Was the current goal the root of a cycle and was the provisional response
+        // different from the final one.
+        if has_been_used && provisional_entry.response != response {
+            // If so, update the provisional reponse for this goal...
+            provisional_entry.response = response;
+            // ...remove all entries whose result depends on this goal
+            // from the provisional cache...
+            //
+            // That's not completely correct, as a nested goal can also
+            // depend on a goal which is lower in the stack so it doesn't
+            // actually depend on the current goal. This should be fairly
+            // rare and is hopefully not relevant for performance.
+            #[allow(rustc::potential_query_instability)]
+            cache.lookup_table.retain(|_key, index| *index <= provisional_entry_index);
+            cache.entries.truncate(provisional_entry_index.index() + 1);
+
+            // ...and finally push our goal back on the stack and reevaluate it.
+            self.stack.push(StackElem { goal, has_been_used: false });
+            false
+        } else {
+            // If not, we're done with this goal.
+            //
+            // Check whether that this goal doesn't depend on a goal deeper on the stack
+            // and if so, move it and all nested goals to the global cache.
+            //
+            // Note that if any nested goal were to depend on something deeper on the stack,
+            // this would have also updated the depth of the current goal.
+            if depth == self.stack.next_index() {
+                for (i, entry) in cache.entries.drain_enumerated(provisional_entry_index.index()..)
+                {
+                    let actual_index = cache.lookup_table.remove(&entry.goal);
+                    debug_assert_eq!(Some(i), actual_index);
+                    debug_assert!(entry.depth == depth);
+                    cache::try_move_finished_goal_to_global_cache(
+                        tcx,
+                        &mut self.overflow_data,
+                        &self.stack,
+                        entry.goal,
+                        entry.response,
+                    );
+                }
+            }
+            true
+        }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs b/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs
new file mode 100644 (file)
index 0000000..1dd3894
--- /dev/null
@@ -0,0 +1,84 @@
+use rustc_infer::infer::canonical::Canonical;
+use rustc_infer::traits::query::NoSolution;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::Limit;
+
+use super::SearchGraph;
+use crate::solve::{response_no_constraints, Certainty, EvalCtxt, MaybeCause, QueryResult};
+
+/// When detecting a solver overflow, we return ambiguity. Overflow can be
+/// *hidden* by either a fatal error in an **AND** or a trivial success in an **OR**.
+///
+/// This is in issue in case of exponential blowup, e.g. if each goal on the stack
+/// has multiple nested (overflowing) candidates. To deal with this, we reduce the limit
+/// used by the solver when hitting the default limit for the first time.
+///
+/// FIXME: Get tests where always using the `default_limit` results in a hang and refer
+/// to them here. We can also improve the overflow strategy if necessary.
+pub(super) struct OverflowData {
+    default_limit: Limit,
+    current_limit: Limit,
+    /// When proving an **AND** we have to repeatedly iterate over the yet unproven goals.
+    ///
+    /// Because of this each iteration also increases the depth in addition to the stack
+    /// depth.
+    additional_depth: usize,
+}
+
+impl OverflowData {
+    pub(super) fn new(tcx: TyCtxt<'_>) -> OverflowData {
+        let default_limit = tcx.recursion_limit();
+        OverflowData { default_limit, current_limit: default_limit, additional_depth: 0 }
+    }
+
+    #[inline]
+    pub(super) fn did_overflow(&self) -> bool {
+        self.default_limit.0 != self.current_limit.0
+    }
+
+    #[inline]
+    pub(super) fn has_overflow(&self, depth: usize) -> bool {
+        !self.current_limit.value_within_limit(depth + self.additional_depth)
+    }
+
+    /// Updating the current limit when hitting overflow.
+    fn deal_with_overflow(&mut self) {
+        // When first hitting overflow we reduce the overflow limit
+        // for all future goals to prevent hangs if there's an exponental
+        // blowup.
+        self.current_limit.0 = self.default_limit.0 / 8;
+    }
+}
+
+impl<'tcx> SearchGraph<'tcx> {
+    pub fn deal_with_overflow(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        goal: Canonical<'tcx, impl Sized>,
+    ) -> QueryResult<'tcx> {
+        self.overflow_data.deal_with_overflow();
+        response_no_constraints(tcx, goal, Certainty::Maybe(MaybeCause::Overflow))
+    }
+}
+
+impl<'tcx> EvalCtxt<'_, 'tcx> {
+    /// A `while`-loop which tracks overflow.
+    pub fn repeat_while_none(
+        &mut self,
+        mut loop_body: impl FnMut(&mut Self) -> Option<Result<Certainty, NoSolution>>,
+    ) -> Result<Certainty, NoSolution> {
+        let start_depth = self.search_graph.overflow_data.additional_depth;
+        let depth = self.search_graph.stack.len();
+        while !self.search_graph.overflow_data.has_overflow(depth) {
+            if let Some(result) = loop_body(self) {
+                self.search_graph.overflow_data.additional_depth = start_depth;
+                return result;
+            }
+
+            self.search_graph.overflow_data.additional_depth += 1;
+        }
+        self.search_graph.overflow_data.additional_depth = start_depth;
+        self.search_graph.overflow_data.deal_with_overflow();
+        Ok(Certainty::Maybe(MaybeCause::Overflow))
+    }
+}
index c69cc39acb53cea516568532d109556cfaee5a86..1ea8fb8fd3dcc8d0d40a2c9dd415e46d808bc101 100644 (file)
@@ -2,58 +2,20 @@
 
 use std::iter;
 
-use super::assembly::{self, AssemblyCtxt};
-use super::{CanonicalGoal, EvalCtxt, Goal, QueryResult};
+use super::assembly::{self, Candidate, CandidateSource};
+use super::infcx_ext::InferCtxtExt;
+use super::{Certainty, EvalCtxt, Goal, QueryResult};
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::InferOk;
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
-use rustc_infer::traits::ObligationCause;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
-use rustc_middle::ty::TraitPredicate;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{TraitPredicate, TypeVisitable};
 use rustc_span::DUMMY_SP;
 
-#[allow(dead_code)] // FIXME: implement and use all variants.
-#[derive(Debug, Clone, Copy)]
-pub(super) enum CandidateSource {
-    /// Some user-defined impl with the given `DefId`.
-    Impl(DefId),
-    /// The n-th caller bound in the `param_env` of our goal.
-    ///
-    /// This is pretty much always a bound from the `where`-clauses of the
-    /// currently checked item.
-    ParamEnv(usize),
-    /// A bound on the `self_ty` in case it is a projection or an opaque type.
-    ///
-    /// # Examples
-    ///
-    /// ```ignore (for syntax highlighting)
-    /// trait Trait {
-    ///     type Assoc: OtherTrait;
-    /// }
-    /// ```
-    ///
-    /// We know that `<Whatever as Trait>::Assoc: OtherTrait` holds by looking at
-    /// the bounds on `Trait::Assoc`.
-    AliasBound(usize),
-    /// A builtin implementation for some specific traits, used in cases
-    /// where we cannot rely an ordinary library implementations.
-    ///
-    /// The most notable examples are `Sized`, `Copy` and `Clone`. This is also
-    /// used for the `DiscriminantKind` and `Pointee` trait, both of which have
-    /// an associated type.
-    Builtin,
-    /// An automatic impl for an auto trait, e.g. `Send`. These impls recursively look
-    /// at the constituent types of the `self_ty` to check whether the auto trait
-    /// is implemented for those.
-    AutoImpl,
-}
-
-type Candidate<'tcx> = assembly::Candidate<'tcx, TraitPredicate<'tcx>>;
+pub mod structural_traits;
 
 impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
-    type CandidateSource = CandidateSource;
-
     fn self_ty(self) -> Ty<'tcx> {
         self.self_ty()
     }
@@ -67,55 +29,247 @@ fn trait_def_id(self, _: TyCtxt<'tcx>) -> DefId {
     }
 
     fn consider_impl_candidate(
-        acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
+        ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
         impl_def_id: DefId,
-    ) {
-        let tcx = acx.cx.tcx;
+    ) -> QueryResult<'tcx> {
+        let tcx = ecx.tcx();
 
-        let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap();
+        let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
         let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
         if iter::zip(goal.predicate.trait_ref.substs, impl_trait_ref.skip_binder().substs)
             .any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
         {
-            return;
+            return Err(NoSolution);
         }
 
-        acx.infcx.probe(|_| {
-            let impl_substs = acx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
+        ecx.infcx.probe(|_| {
+            let impl_substs = ecx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
             let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
 
-            let Ok(InferOk { obligations, .. }) = acx
-                .infcx
-                .at(&ObligationCause::dummy(), goal.param_env)
-                .define_opaque_types(false)
-                .eq(goal.predicate.trait_ref, impl_trait_ref)
-                .map_err(|e| debug!("failed to equate trait refs: {e:?}"))
-            else {
-                return
-            };
+            let mut nested_goals =
+                ecx.infcx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
             let where_clause_bounds = tcx
                 .predicates_of(impl_def_id)
                 .instantiate(tcx, impl_substs)
                 .predicates
                 .into_iter()
                 .map(|pred| goal.with(tcx, pred));
+            nested_goals.extend(where_clause_bounds);
+            ecx.evaluate_all_and_make_canonical_response(nested_goals)
+        })
+    }
 
-            let nested_goals =
-                obligations.into_iter().map(|o| o.into()).chain(where_clause_bounds).collect();
+    fn consider_assumption(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        assumption: ty::Predicate<'tcx>,
+    ) -> QueryResult<'tcx> {
+        if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
+            && poly_trait_pred.def_id() == goal.predicate.def_id()
+        {
+            // FIXME: Constness and polarity
+            ecx.infcx.probe(|_| {
+                let assumption_trait_pred =
+                    ecx.infcx.instantiate_bound_vars_with_infer(poly_trait_pred);
+                let nested_goals = ecx.infcx.eq(
+                    goal.param_env,
+                    goal.predicate.trait_ref,
+                    assumption_trait_pred.trait_ref,
+                )?;
+                ecx.evaluate_all_and_make_canonical_response(nested_goals)
+            })
+        } else {
+            Err(NoSolution)
+        }
+    }
+
+    fn consider_auto_trait_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        ecx.probe_and_evaluate_goal_for_constituent_tys(
+            goal,
+            structural_traits::instantiate_constituent_tys_for_auto_trait,
+        )
+    }
+
+    fn consider_trait_alias_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let tcx = ecx.tcx();
 
-            let Ok(certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return };
-            acx.try_insert_candidate(CandidateSource::Impl(impl_def_id), certainty);
+        ecx.infcx.probe(|_| {
+            let nested_obligations = tcx
+                .predicates_of(goal.predicate.def_id())
+                .instantiate(tcx, goal.predicate.trait_ref.substs);
+            ecx.evaluate_all_and_make_canonical_response(
+                nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)).collect(),
+            )
         })
     }
+
+    fn consider_builtin_sized_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        ecx.probe_and_evaluate_goal_for_constituent_tys(
+            goal,
+            structural_traits::instantiate_constituent_tys_for_sized_trait,
+        )
+    }
+
+    fn consider_builtin_copy_clone_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        ecx.probe_and_evaluate_goal_for_constituent_tys(
+            goal,
+            structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
+        )
+    }
+
+    fn consider_builtin_pointer_sized_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        if goal.predicate.self_ty().has_non_region_infer() {
+            return ecx.make_canonical_response(Certainty::AMBIGUOUS);
+        }
+
+        let tcx = ecx.tcx();
+        let self_ty = tcx.erase_regions(goal.predicate.self_ty());
+
+        if let Ok(layout) = tcx.layout_of(goal.param_env.and(self_ty))
+            &&  let usize_layout = tcx.layout_of(ty::ParamEnv::empty().and(tcx.types.usize)).unwrap().layout
+            && layout.layout.size() == usize_layout.size()
+            && layout.layout.align().abi == usize_layout.align().abi
+        {
+            // FIXME: We could make this faster by making a no-constraints response
+            ecx.make_canonical_response(Certainty::Yes)
+        } else {
+            Err(NoSolution)
+        }
+    }
+
+    fn consider_builtin_fn_trait_candidates(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        goal_kind: ty::ClosureKind,
+    ) -> QueryResult<'tcx> {
+        if let Some(tupled_inputs_and_output) =
+            structural_traits::extract_tupled_inputs_and_output_from_callable(
+                ecx.tcx(),
+                goal.predicate.self_ty(),
+                goal_kind,
+            )?
+        {
+            let pred = tupled_inputs_and_output
+                .map_bound(|(inputs, _)| {
+                    ecx.tcx()
+                        .mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
+                })
+                .to_predicate(ecx.tcx());
+            Self::consider_assumption(ecx, goal, pred)
+        } else {
+            ecx.make_canonical_response(Certainty::AMBIGUOUS)
+        }
+    }
+
+    fn consider_builtin_tuple_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
+            ecx.make_canonical_response(Certainty::Yes)
+        } else {
+            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> {
+impl<'tcx> EvalCtxt<'_, 'tcx> {
+    /// Convenience function for traits that are structural, i.e. that only
+    /// have nested subgoals that only change the self type. Unlike other
+    /// evaluate-like helpers, this does a probe, so it doesn't need to be
+    /// wrapped in one.
+    fn probe_and_evaluate_goal_for_constituent_tys(
+        &mut self,
+        goal: Goal<'tcx, TraitPredicate<'tcx>>,
+        constituent_tys: impl Fn(&InferCtxt<'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>,
+    ) -> QueryResult<'tcx> {
+        self.infcx.probe(|_| {
+            self.evaluate_all_and_make_canonical_response(
+                constituent_tys(self.infcx, goal.predicate.self_ty())?
+                    .into_iter()
+                    .map(|ty| {
+                        goal.with(
+                            self.tcx(),
+                            ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)),
+                        )
+                    })
+                    .collect(),
+            )
+        })
+    }
+
     pub(super) fn compute_trait_goal(
         &mut self,
-        goal: CanonicalGoal<'tcx, TraitPredicate<'tcx>>,
+        goal: Goal<'tcx, TraitPredicate<'tcx>>,
     ) -> QueryResult<'tcx> {
-        let candidates = AssemblyCtxt::assemble_and_evaluate_candidates(self, goal);
+        let candidates = self.assemble_and_evaluate_candidates(goal);
         self.merge_trait_candidates_discard_reservation_impls(candidates)
     }
 
@@ -168,15 +322,14 @@ fn trait_candidate_should_be_dropped_in_favor_of(
         match (candidate.source, other.source) {
             (CandidateSource::Impl(_), _)
             | (CandidateSource::ParamEnv(_), _)
-            | (CandidateSource::AliasBound(_), _)
-            | (CandidateSource::Builtin, _)
-            | (CandidateSource::AutoImpl, _) => unimplemented!(),
+            | (CandidateSource::AliasBound, _)
+            | (CandidateSource::BuiltinImpl, _) => unimplemented!(),
         }
     }
 
     fn discard_reservation_impl(&self, candidate: Candidate<'tcx>) -> Candidate<'tcx> {
         if let CandidateSource::Impl(def_id) = candidate.source {
-            if let ty::ImplPolarity::Reservation = self.tcx.impl_polarity(def_id) {
+            if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) {
                 debug!("Selected reservation impl");
                 // FIXME: reduce candidate to ambiguous
                 // FIXME: replace `var_values` with identity, yeet external constraints.
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
new file mode 100644 (file)
index 0000000..5007a01
--- /dev/null
@@ -0,0 +1,237 @@
+use rustc_hir::{Movability, Mutability};
+use rustc_infer::{infer::InferCtxt, traits::query::NoSolution};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+
+// Calculates the constituent types of a type for `auto trait` purposes.
+//
+// For types with an "existential" binder, i.e. generator witnesses, we also
+// instantiate the binder with placeholders eagerly.
+pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Result<Vec<Ty<'tcx>>, NoSolution> {
+    let tcx = infcx.tcx;
+    match *ty.kind() {
+        ty::Uint(_)
+        | ty::Int(_)
+        | ty::Bool
+        | ty::Float(_)
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::Str
+        | ty::Error(_)
+        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+        | ty::Never
+        | ty::Char => Ok(vec![]),
+
+        ty::Dynamic(..)
+        | ty::Param(..)
+        | ty::Foreign(..)
+        | ty::Alias(ty::Projection, ..)
+        | ty::Placeholder(..) => Err(NoSolution),
+
+        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])
+        }
+
+        ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]),
+
+        ty::Tuple(ref tys) => {
+            // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
+            Ok(tys.iter().collect())
+        }
+
+        ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
+
+        ty::Generator(_, ref substs, _) => {
+            let generator_substs = substs.as_generator();
+            Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()])
+        }
+
+        ty::GeneratorWitness(types) => {
+            Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
+        }
+
+        ty::GeneratorWitnessMIR(..) => todo!(),
+
+        // For `PhantomData<T>`, we pass `T`.
+        ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]),
+
+        ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()),
+
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
+            // We can resolve the `impl Trait` to its concrete type,
+            // which enforces a DAG between the functions requiring
+            // the auto trait bounds in question.
+            Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)])
+        }
+    }
+}
+
+pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Result<Vec<Ty<'tcx>>, NoSolution> {
+    match *ty.kind() {
+        ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+        | ty::Uint(_)
+        | ty::Int(_)
+        | ty::Bool
+        | ty::Float(_)
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::RawPtr(..)
+        | ty::Char
+        | ty::Ref(..)
+        | ty::Generator(..)
+        | ty::GeneratorWitness(..)
+        | ty::GeneratorWitnessMIR(..)
+        | ty::Array(..)
+        | ty::Closure(..)
+        | ty::Never
+        | ty::Dynamic(_, _, ty::DynStar)
+        | ty::Error(_) => Ok(vec![]),
+
+        ty::Str
+        | ty::Slice(_)
+        | ty::Dynamic(..)
+        | ty::Foreign(..)
+        | ty::Alias(..)
+        | ty::Param(_)
+        | ty::Placeholder(..) => Err(NoSolution),
+
+        ty::Bound(..)
+        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            bug!("unexpected type `{ty}`")
+        }
+
+        ty::Tuple(tys) => Ok(tys.to_vec()),
+
+        ty::Adt(def, substs) => {
+            let sized_crit = def.sized_constraint(infcx.tcx);
+            Ok(sized_crit
+                .0
+                .iter()
+                .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs))
+                .collect())
+        }
+    }
+}
+
+pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Result<Vec<Ty<'tcx>>, NoSolution> {
+    match *ty.kind() {
+        ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::Error(_) => Ok(vec![]),
+
+        // Implementations are provided in core
+        ty::Uint(_)
+        | ty::Int(_)
+        | ty::Bool
+        | ty::Float(_)
+        | ty::Char
+        | ty::RawPtr(..)
+        | ty::Never
+        | ty::Ref(_, _, Mutability::Not)
+        | ty::Array(..) => Err(NoSolution),
+
+        ty::Dynamic(..)
+        | ty::Str
+        | ty::Slice(_)
+        | ty::Generator(_, _, Movability::Static)
+        | ty::Foreign(..)
+        | ty::Ref(_, _, Mutability::Mut)
+        | ty::Adt(_, _)
+        | ty::Alias(_, _)
+        | ty::Param(_)
+        | ty::Placeholder(..) => Err(NoSolution),
+
+        ty::Bound(..)
+        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            bug!("unexpected type `{ty}`")
+        }
+
+        ty::Tuple(tys) => Ok(tys.to_vec()),
+
+        ty::Closure(_, substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
+
+        ty::Generator(_, substs, Movability::Movable) => {
+            if infcx.tcx.features().generator_clone {
+                let generator = substs.as_generator();
+                Ok(vec![generator.tupled_upvars_ty(), generator.witness()])
+            } else {
+                Err(NoSolution)
+            }
+        }
+
+        ty::GeneratorWitness(types) => {
+            Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
+        }
+
+        ty::GeneratorWitnessMIR(..) => todo!(),
+    }
+}
+
+// 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>,
+    goal_kind: ty::ClosureKind,
+) -> Result<Option<ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>)>>, NoSolution> {
+    match *self_ty.kind() {
+        ty::FnDef(def_id, substs) => Ok(Some(
+            tcx.fn_sig(def_id)
+                .subst(tcx, substs)
+                .map_bound(|sig| (tcx.mk_tup(sig.inputs().iter()), sig.output())),
+        )),
+        ty::FnPtr(sig) => {
+            Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs().iter()), sig.output()))))
+        }
+        ty::Closure(_, substs) => {
+            let closure_substs = substs.as_closure();
+            match closure_substs.kind_ty().to_opt_closure_kind() {
+                Some(closure_kind) if closure_kind.extends(goal_kind) => {}
+                None => return Ok(None),
+                _ => return Err(NoSolution),
+            }
+            Ok(Some(closure_substs.sig().map_bound(|sig| (sig.inputs()[0], sig.output()))))
+        }
+        ty::Bool
+        | ty::Char
+        | ty::Int(_)
+        | ty::Uint(_)
+        | ty::Float(_)
+        | ty::Adt(_, _)
+        | ty::Foreign(_)
+        | ty::Str
+        | ty::Array(_, _)
+        | ty::Slice(_)
+        | ty::RawPtr(_)
+        | ty::Ref(_, _, _)
+        | ty::Dynamic(_, _, _)
+        | ty::Generator(_, _, _)
+        | ty::GeneratorWitness(_)
+        | ty::GeneratorWitnessMIR(..)
+        | ty::Never
+        | ty::Tuple(_)
+        | ty::Alias(_, _)
+        | ty::Param(_)
+        | 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 e88950523537f23ba2494ba122e1a9e10447c120..e26bef0b8b7f5c11266b62ae0083304b82580d9a 100644 (file)
@@ -7,24 +7,18 @@
     ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
     SelectionError, TraitEngine,
 };
-use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_middle::ty::{self, TypeVisitable};
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_middle::ty::TypeVisitable;
 
 pub struct FulfillmentContext<'tcx> {
     obligations: FxIndexSet<PredicateObligation<'tcx>>,
 
-    relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
-
     usable_in_snapshot: bool,
 }
 
 impl FulfillmentContext<'_> {
     pub(super) fn new() -> Self {
-        FulfillmentContext {
-            obligations: FxIndexSet::default(),
-            relationships: FxHashMap::default(),
-            usable_in_snapshot: false,
-        }
+        FulfillmentContext { obligations: FxIndexSet::default(), usable_in_snapshot: false }
     }
 
     pub(crate) fn new_in_snapshot() -> Self {
@@ -43,20 +37,10 @@ fn register_predicate_obligation(
         }
         let obligation = infcx.resolve_vars_if_possible(obligation);
 
-        super::relationships::update(self, infcx, &obligation);
-
         self.obligations.insert(obligation);
     }
 
-    fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
-        {
-            let errors = self.select_where_possible(infcx);
-
-            if !errors.is_empty() {
-                return errors;
-            }
-        }
-
+    fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
         // any remaining obligations are errors
         self.obligations
             .iter()
@@ -151,11 +135,14 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
         errors
     }
 
-    fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
-        self.obligations.iter().cloned().collect()
+    fn drain_unstalled_obligations(
+        &mut self,
+        _: &InferCtxt<'tcx>,
+    ) -> Vec<PredicateObligation<'tcx>> {
+        unimplemented!()
     }
 
-    fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
-        &mut self.relationships
+    fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
+        self.obligations.iter().cloned().collect()
     }
 }
index 258d2e2d28c9db5db8efc8e8dfcfb9b734d20be0..61f508a7a0750c37746591d9c94ac3f14106b25d 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;
@@ -80,7 +79,7 @@ pub fn overlapping_impls(
     let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
     let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
     let may_overlap = match (impl1_ref, impl2_ref) {
-        (Some(a), Some(b)) => iter::zip(a.substs, b.substs)
+        (Some(a), Some(b)) => iter::zip(a.skip_binder().substs, b.skip_binder().substs)
             .all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)),
         (None, None) => {
             let self_ty1 = tcx.type_of(impl1_def_id);
@@ -126,7 +125,7 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
     let header = ty::ImplHeader {
         impl_def_id,
         self_ty: tcx.bound_type_of(impl_def_id).subst(tcx, impl_substs),
-        trait_ref: tcx.bound_impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)),
+        trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)),
         predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates,
     };
 
@@ -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);
@@ -401,12 +396,12 @@ fn resolve_negative_obligation<'tcx>(
     infcx.resolve_regions(&outlives_env).is_empty()
 }
 
+#[instrument(level = "debug", skip(tcx), ret)]
 pub fn trait_ref_is_knowable<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
 ) -> Result<(), Conflict> {
-    debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref);
-    if orphan_check_trait_ref(tcx, trait_ref, InCrate::Remote).is_ok() {
+    if orphan_check_trait_ref(trait_ref, InCrate::Remote).is_ok() {
         // A downstream or cousin crate is allowed to implement some
         // substitution of this trait-ref.
         return Err(Conflict::Downstream);
@@ -429,11 +424,9 @@ pub fn trait_ref_is_knowable<'tcx>(
     // and if we are an intermediate owner, then we don't care
     // about future-compatibility, which means that we're OK if
     // we are an owner.
-    if orphan_check_trait_ref(tcx, trait_ref, InCrate::Local).is_ok() {
-        debug!("trait_ref_is_knowable: orphan check passed");
+    if orphan_check_trait_ref(trait_ref, InCrate::Local).is_ok() {
         Ok(())
     } else {
-        debug!("trait_ref_is_knowable: nonlocal, nonfundamental, unowned");
         Err(Conflict::Upstream)
     }
 }
@@ -445,6 +438,7 @@ pub fn trait_ref_is_local_or_fundamental<'tcx>(
     trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental)
 }
 
+#[derive(Debug)]
 pub enum OrphanCheckErr<'tcx> {
     NonLocalInputType(Vec<(Ty<'tcx>, bool /* Is this the first input type? */)>),
     UncoveredTy(Ty<'tcx>, Option<Ty<'tcx>>),
@@ -456,13 +450,12 @@ pub enum OrphanCheckErr<'tcx> {
 ///
 /// 1. All type parameters in `Self` must be "covered" by some local type constructor.
 /// 2. Some local type must appear in `Self`.
+#[instrument(level = "debug", skip(tcx), ret)]
 pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanCheckErr<'_>> {
-    debug!("orphan_check({:?})", impl_def_id);
-
     // We only except this routine to be invoked on implementations
     // of a trait, not inherent implementations.
-    let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
-    debug!("orphan_check: trait_ref={:?}", trait_ref);
+    let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
+    debug!(?trait_ref);
 
     // If the *trait* is local to the crate, ok.
     if trait_ref.def_id.is_local() {
@@ -470,7 +463,7 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
         return Ok(());
     }
 
-    orphan_check_trait_ref(tcx, trait_ref, InCrate::Local)
+    orphan_check_trait_ref(trait_ref, InCrate::Local)
 }
 
 /// Checks whether a trait-ref is potentially implementable by a crate.
@@ -559,13 +552,11 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
 ///
 /// Note that this function is never called for types that have both type
 /// parameters and inference variables.
+#[instrument(level = "trace", ret)]
 fn orphan_check_trait_ref<'tcx>(
-    tcx: TyCtxt<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
     in_crate: InCrate,
 ) -> Result<(), OrphanCheckErr<'tcx>> {
-    debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate);
-
     if trait_ref.needs_infer() && trait_ref.needs_subst() {
         bug!(
             "can't orphan check a trait ref with both params and inference variables {:?}",
@@ -573,7 +564,7 @@ fn orphan_check_trait_ref<'tcx>(
         );
     }
 
-    let mut checker = OrphanChecker::new(tcx, in_crate);
+    let mut checker = OrphanChecker::new(in_crate);
     match trait_ref.visit_with(&mut checker) {
         ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
         ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => {
@@ -592,7 +583,6 @@ fn orphan_check_trait_ref<'tcx>(
 }
 
 struct OrphanChecker<'tcx> {
-    tcx: TyCtxt<'tcx>,
     in_crate: InCrate,
     in_self_ty: bool,
     /// Ignore orphan check failures and exclusively search for the first
@@ -602,9 +592,8 @@ struct OrphanChecker<'tcx> {
 }
 
 impl<'tcx> OrphanChecker<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, in_crate: InCrate) -> Self {
+    fn new(in_crate: InCrate) -> Self {
         OrphanChecker {
-            tcx,
             in_crate,
             in_self_ty: true,
             search_first_local_ty: false,
@@ -614,12 +603,12 @@ fn new(tcx: TyCtxt<'tcx>, in_crate: InCrate) -> Self {
 
     fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> {
         self.non_local_tys.push((t, self.in_self_ty));
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 
     fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> {
         if self.search_first_local_ty {
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         } else {
             ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t))
         }
@@ -641,7 +630,7 @@ enum OrphanCheckEarlyExit<'tcx> {
 impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
     type BreakTy = OrphanCheckEarlyExit<'tcx>;
     fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -697,11 +686,17 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 }
             }
             ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
-            ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
-                self.tcx.sess.delay_span_bug(
-                    DUMMY_SP,
-                    format!("ty_is_local invoked on closure or generator: {:?}", ty),
-                );
+            ty::Closure(did, ..) | ty::Generator(did, ..) => {
+                if self.def_id_is_local(did) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                } else {
+                    self.found_non_local_ty(ty)
+                }
+            }
+            // This should only be created when checking whether we have to check whether some
+            // auto trait impl applies. There will never be multiple impls, so we can just
+            // act as if it were a local type here.
+            ty::GeneratorWitness(_) | ty::GeneratorWitnessMIR(..) => {
                 ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
             }
             ty::Alias(ty::Opaque, ..) => {
@@ -756,6 +751,6 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
     /// parameters, allowing uncovered const parameters in impls seems more useful
     /// than allowing `impl<T> Trait<local_fn_ptr, T> for i32` to compile.
     fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 }
index 71fb6058cd2c54e722a0be82f736dd295f7b9ceb..f779d9dd8d93560302988bd9d03d981eda133ae8 100644 (file)
@@ -198,7 +198,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
                 // If we start allowing directly writing `ConstKind::Expr` without an intermediate anon const
                 // this will be incorrect. It might be worth investigating making `predicates_of` elaborate
                 // all of the `ConstEvaluatable` bounds rather than having a visitor here.
-                ControlFlow::CONTINUE
+                ControlFlow::Continue(())
             }
         }
     }
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 0c1717cff332c40e79bede7a633994be3c054155..6bf453c3ff084376b2afa27c74384acbf4e5a8bd 100644 (file)
@@ -27,7 +27,7 @@ pub fn recompute_applicable_impls<'tcx>(
             ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
 
         let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
-        let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs);
+        let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs);
         let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
 
         if let Err(_) =
@@ -81,10 +81,8 @@ pub fn recompute_applicable_impls<'tcx>(
     );
 
     let predicates =
-        tcx.predicates_of(obligation.cause.body_id.owner.to_def_id()).instantiate_identity(tcx);
-    for obligation in
-        elaborate_predicates_with_span(tcx, std::iter::zip(predicates.predicates, predicates.spans))
-    {
+        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()
             && param_env_candidate_may_apply(kind.rebind(trait_pred))
index 0c7ffb056cc0256e4177ba9a4a1aba7943eba29e..e9842b2cba516a6d692f71765f86b1b2e0a366d9 100644 (file)
@@ -101,6 +101,18 @@ fn type_implements_fn_trait(
 }
 
 pub trait TypeErrCtxtExt<'tcx> {
+    fn build_overflow_error<T>(
+        &self,
+        predicate: &T,
+        span: Span,
+        suggest_increasing_limit: bool,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
+    where
+        T: fmt::Display
+            + TypeFoldable<'tcx>
+            + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
+        <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
+
     fn report_overflow_error<T>(
         &self,
         predicate: &T,
@@ -374,6 +386,7 @@ fn type_implements_fn_trait(
         })
     }
 }
+
 impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     fn report_fulfillment_errors(
         &self,
@@ -453,9 +466,11 @@ struct ErrorDescriptor<'tcx> {
             }
         }
 
-        for (error, suppressed) in iter::zip(errors, is_suppressed) {
-            if !suppressed {
-                self.report_fulfillment_error(error, body_id);
+        for from_expansion in [false, true] {
+            for (error, suppressed) in iter::zip(errors, &is_suppressed) {
+                if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
+                    self.report_fulfillment_error(error, body_id);
+                }
             }
         }
 
@@ -475,6 +490,26 @@ fn report_overflow_error<T>(
         suggest_increasing_limit: bool,
         mutate: impl FnOnce(&mut Diagnostic),
     ) -> !
+    where
+        T: fmt::Display
+            + TypeFoldable<'tcx>
+            + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
+        <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
+    {
+        let mut err = self.build_overflow_error(predicate, span, suggest_increasing_limit);
+        mutate(&mut err);
+        err.emit();
+
+        self.tcx.sess.abort_if_errors();
+        bug!();
+    }
+
+    fn build_overflow_error<T>(
+        &self,
+        predicate: &T,
+        span: Span,
+        suggest_increasing_limit: bool,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
     where
         T: fmt::Display
             + TypeFoldable<'tcx>
@@ -508,11 +543,7 @@ fn report_overflow_error<T>(
             self.suggest_new_overflow_limit(&mut err);
         }
 
-        mutate(&mut err);
-
-        err.emit();
-        self.tcx.sess.abort_if_errors();
-        bug!();
+        err
     }
 
     /// Reports that an overflow has occurred and halts compilation. We
@@ -836,14 +867,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);
                         }
 
@@ -852,6 +876,29 @@ fn report_selection_error(
                         let mut suggested =
                             self.suggest_dereferences(&obligation, &mut err, trait_predicate);
                         suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate);
+                        let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
+                        suggested = if let &[cand] = &impl_candidates[..] {
+                            let cand = cand.trait_ref;
+                            if let (ty::FnPtr(_), ty::FnDef(..)) =
+                                (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind())
+                            {
+                                err.span_suggestion(
+                                    span.shrink_to_hi(),
+                                    format!(
+                                        "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`",
+                                        cand.print_only_trait_path(),
+                                        cand.self_ty(),
+                                    ),
+                                    format!(" as {}", cand.self_ty()),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                true
+                            } else {
+                                false
+                            }
+                        } else {
+                            false
+                        } || suggested;
                         suggested |=
                             self.suggest_remove_reference(&obligation, &mut err, trait_predicate);
                         suggested |= self.suggest_semicolon_removal(
@@ -908,6 +955,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(
@@ -988,7 +1037,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,
                             ) {
@@ -1024,7 +1073,7 @@ fn report_selection_error(
                                     self.report_similar_impl_candidates(
                                         impl_candidates,
                                         trait_ref,
-                                        obligation.cause.body_id,
+                                        body_hir_id,
                                         &mut err,
                                         true,
                                     );
@@ -1324,6 +1373,7 @@ fn report_selection_error(
                         expected_trait_ref,
                         obligation.cause.code(),
                         found_node,
+                        obligation.param_env,
                     )
                 } else {
                     let (closure_span, closure_arg_span, found) = found_did
@@ -1869,6 +1919,7 @@ fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> {
                 ty::Generator(..) => Some(16),
                 ty::Foreign(..) => Some(17),
                 ty::GeneratorWitness(..) => Some(18),
+                ty::GeneratorWitnessMIR(..) => Some(19),
                 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
             }
         }
@@ -1940,7 +1991,7 @@ fn find_similar_impl_candidates(
                     return None;
                 }
 
-                let imp = self.tcx.impl_trait_ref(def_id).unwrap();
+                let imp = self.tcx.impl_trait_ref(def_id).unwrap().skip_binder();
 
                 self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false)
                     .map(|similarity| ImplCandidate { trait_ref: imp, similarity })
@@ -1968,27 +2019,25 @@ fn report_similar_impl_candidates(
             candidates.sort();
             candidates.dedup();
             let len = candidates.len();
-            if candidates.len() == 0 {
+            if candidates.is_empty() {
                 return false;
             }
-            if candidates.len() == 1 {
-                let ty_desc = match candidates[0].self_ty().kind() {
-                    ty::FnPtr(_) => Some("fn pointer"),
-                    _ => None,
-                };
-                let the_desc = match ty_desc {
-                    Some(desc) => format!(" implemented for {} `", desc),
-                    None => " implemented for `".to_string(),
-                };
+            if let &[cand] = &candidates[..] {
+                let (desc, mention_castable) =
+                    match (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) {
+                        (ty::FnPtr(_), ty::FnDef(..)) => {
+                            (" implemented for fn pointer `", ", cast using `as`")
+                        }
+                        (ty::FnPtr(_), _) => (" implemented for fn pointer `", ""),
+                        _ => (" implemented for `", ""),
+                    };
                 err.highlighted_help(vec![
-                    (
-                        format!("the trait `{}` ", candidates[0].print_only_trait_path()),
-                        Style::NoStyle,
-                    ),
+                    (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle),
                     ("is".to_string(), Style::Highlight),
-                    (the_desc, Style::NoStyle),
-                    (candidates[0].self_ty().to_string(), Style::Highlight),
+                    (desc.to_string(), Style::NoStyle),
+                    (cand.self_ty().to_string(), Style::Highlight),
                     ("`".to_string(), Style::NoStyle),
+                    (mention_castable.to_string(), Style::NoStyle),
                 ]);
                 return true;
             }
@@ -2040,6 +2089,7 @@ fn report_similar_impl_candidates(
                         || self.tcx.is_builtin_derive(def_id)
                 })
                 .filter_map(|def_id| self.tcx.impl_trait_ref(def_id))
+                .map(ty::EarlyBinder::subst_identity)
                 .filter(|trait_ref| {
                     let self_ty = trait_ref.self_ty();
                     // Avoid mentioning type parameters.
@@ -2193,7 +2243,7 @@ fn maybe_report_ambiguity(
                 // This is kind of a hack: it frequently happens that some earlier
                 // error prevents types from being fully inferred, and then we get
                 // a bunch of uninteresting errors saying something like "<generic
-                // #0> doesn't implement Sized".  It may even be true that we
+                // #0> doesn't implement Sized". It may even be true that we
                 // could just skip over all checks where the self-ty is an
                 // inference variable, but I was afraid that there might be an
                 // inference variable created, registered as an obligation, and
@@ -2279,10 +2329,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,
                                 );
@@ -2802,7 +2854,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 }
     }
 }
@@ -2907,11 +2959,12 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) {
             ControlFlow::Break(())
         } else {
-            ControlFlow::CONTINUE
+            ControlFlow::Continue(())
         }
     }
 }
 
+#[derive(Copy, Clone)]
 pub enum DefIdOrName {
     DefId(DefId),
     Name(&'static str),
index e599996230f51691b87c4a97c34d2195d2307739..a3209d35e58be577186af66ae55e9ccde446603e 100644 (file)
@@ -68,7 +68,7 @@ fn impl_similar_to(
 
         self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
             let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
-            let impl_trait_ref = tcx.bound_impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);
+            let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);
 
             let impl_self_ty = impl_trait_ref.self_ty();
 
@@ -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 1b98ead29f851d96e076703361ea7053be52d9d0..b35b9d62759c73267bf4d3f217616a6305b23592 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(
@@ -212,6 +213,13 @@ fn suggest_add_clone_to_arg(
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool;
 
+    fn extract_callable_info(
+        &self,
+        hir_id: HirId,
+        param_env: ty::ParamEnv<'tcx>,
+        found: Ty<'tcx>,
+    ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>;
+
     fn suggest_add_reference_to_arg(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -276,6 +284,7 @@ fn report_closure_arg_mismatch(
         expected: ty::PolyTraitRef<'tcx>,
         cause: &ObligationCauseCode<'tcx>,
         found_node: Option<Node<'_>>,
+        param_env: ty::ParamEnv<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
 
     fn note_conflicting_closure_bounds(
@@ -390,7 +399,7 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -
 /// param for cleaner code.
 fn suggest_restriction<'tcx>(
     tcx: TyCtxt<'tcx>,
-    hir_id: HirId,
+    item_id: LocalDefId,
     hir_generics: &hir::Generics<'tcx>,
     msg: &str,
     err: &mut Diagnostic,
@@ -409,7 +418,6 @@ fn suggest_restriction<'tcx>(
     {
         return;
     }
-    let Some(item_id) = hir_id.as_owner() else { return; };
     let generics = tcx.generics_of(item_id);
     // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`...
     if let Some((param, bound_str, fn_sig)) =
@@ -514,7 +522,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,
+        mut body_id: LocalDefId,
     ) {
         let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
 
@@ -527,8 +535,7 @@ 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) {
+        while let Some(node) = self.tcx.hir().find_by_def_id(body_id) {
             match node {
                 hir::Node::Item(hir::Item {
                     ident,
@@ -539,7 +546,7 @@ fn suggest_restricting_param_bound(
                     // Restricting `Self` for a single method.
                     suggest_restriction(
                         self.tcx,
-                        hir_id,
+                        body_id,
                         &generics,
                         "`Self`",
                         err,
@@ -559,7 +566,7 @@ fn suggest_restricting_param_bound(
                     assert!(param_ty);
                     // Restricting `Self` for a single method.
                     suggest_restriction(
-                        self.tcx, hir_id, &generics, "`Self`", err, None, projection, trait_pred,
+                        self.tcx, body_id, &generics, "`Self`", err, None, projection, trait_pred,
                         None,
                     );
                     return;
@@ -581,7 +588,7 @@ fn suggest_restricting_param_bound(
                     // Missing restriction on associated type of type parameter (unmet projection).
                     suggest_restriction(
                         self.tcx,
-                        hir_id,
+                        body_id,
                         &generics,
                         "the associated type",
                         err,
@@ -601,7 +608,7 @@ fn suggest_restricting_param_bound(
                     // Missing restriction on associated type of type parameter (unmet projection).
                     suggest_restriction(
                         self.tcx,
-                        hir_id,
+                        body_id,
                         &generics,
                         "the associated type",
                         err,
@@ -705,8 +712,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);
         }
     }
 
@@ -878,6 +884,12 @@ fn suggest_fn_call(
         err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
+        // It doesn't make sense to make this suggestion outside of typeck...
+        // (also autoderef will ICE...)
+        if self.typeck_results.is_none() {
+            return false;
+        }
+
         if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = obligation.predicate.kind().skip_binder()
             && Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait()
         {
@@ -885,92 +897,18 @@ fn suggest_fn_call(
             return false;
         }
 
-        // This is duplicated from `extract_callable_info` in typeck, which
-        // relies on autoderef, so we can't use it here.
-        let found = trait_pred.self_ty().skip_binder().peel_refs();
-        let Some((def_id_or_name, output, inputs)) = (match *found.kind()
-        {
-            ty::FnPtr(fn_sig) => {
-                Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs()))
-            }
-            ty::FnDef(def_id, _) => {
-                let fn_sig = found.fn_sig(self.tcx);
-                Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
-            }
-            ty::Closure(def_id, substs) => {
-                let fn_sig = substs.as_closure().sig();
-                Some((
-                    DefIdOrName::DefId(def_id),
-                    fn_sig.output(),
-                    fn_sig.inputs().map_bound(|inputs| &inputs[1..]),
-                ))
-            }
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
-                self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
-                    if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
-                    && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
-                    // args tuple will always be substs[1]
-                    && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
-                    {
-                        Some((
-                            DefIdOrName::DefId(def_id),
-                            pred.kind().rebind(proj.term.ty().unwrap()),
-                            pred.kind().rebind(args.as_slice()),
-                        ))
-                    } else {
-                        None
-                    }
-                })
-            }
-            ty::Dynamic(data, _, ty::Dyn) => {
-                data.iter().find_map(|pred| {
-                    if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
-                    && Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
-                    // for existential projection, substs are shifted over by 1
-                    && let ty::Tuple(args) = proj.substs.type_at(0).kind()
-                    {
-                        Some((
-                            DefIdOrName::Name("trait object"),
-                            pred.rebind(proj.term.ty().unwrap()),
-                            pred.rebind(args.as_slice()),
-                        ))
-                    } else {
-                        None
-                    }
-                })
-            }
-            ty::Param(_) => {
-                obligation.param_env.caller_bounds().iter().find_map(|pred| {
-                    if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
-                    && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
-                    && proj.projection_ty.self_ty() == found
-                    // args tuple will always be substs[1]
-                    && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
-                    {
-                        Some((
-                            DefIdOrName::Name("type parameter"),
-                            pred.kind().rebind(proj.term.ty().unwrap()),
-                            pred.kind().rebind(args.as_slice()),
-                        ))
-                    } else {
-                        None
-                    }
-                })
-            }
-            _ => None,
-        }) else { return false; };
-        let output = self.replace_bound_vars_with_fresh_vars(
-            obligation.cause.span,
+        let self_ty = self.replace_bound_vars_with_fresh_vars(
+            DUMMY_SP,
             LateBoundRegionConversionTime::FnCall,
-            output,
+            trait_pred.self_ty(),
         );
-        let inputs = inputs.skip_binder().iter().map(|ty| {
-            self.replace_bound_vars_with_fresh_vars(
-                obligation.cause.span,
-                LateBoundRegionConversionTime::FnCall,
-                inputs.rebind(*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(
+            body_hir_id,
+            obligation.param_env,
+            self_ty,
+        ) else { return false; };
 
         // Remapping bound vars here
         let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output));
@@ -998,6 +936,7 @@ fn suggest_fn_call(
         };
 
         let args = inputs
+            .into_iter()
             .map(|ty| {
                 if ty.is_suggestable(self.tcx, false) {
                     format!("/* {ty} */")
@@ -1064,8 +1003,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; };
@@ -1120,8 +1060,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 };
@@ -1161,6 +1100,121 @@ fn suggest_add_clone_to_arg(
         false
     }
 
+    /// 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,
+        param_env: ty::ParamEnv<'tcx>,
+        found: Ty<'tcx>,
+    ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
+        // Autoderef is useful here because sometimes we box callables, etc.
+        let Some((def_id_or_name, output, inputs)) = (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| {
+            match *found.kind() {
+                ty::FnPtr(fn_sig) =>
+                    Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())),
+                ty::FnDef(def_id, _) => {
+                    let fn_sig = found.fn_sig(self.tcx);
+                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
+                }
+                ty::Closure(def_id, substs) => {
+                    let fn_sig = substs.as_closure().sig();
+                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
+                }
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
+                    self.tcx.item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
+                        if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
+                        && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
+                        // args tuple will always be substs[1]
+                        && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+                        {
+                            Some((
+                                DefIdOrName::DefId(def_id),
+                                pred.kind().rebind(proj.term.ty().unwrap()),
+                                pred.kind().rebind(args.as_slice()),
+                            ))
+                        } else {
+                            None
+                        }
+                    })
+                }
+                ty::Dynamic(data, _, ty::Dyn) => {
+                    data.iter().find_map(|pred| {
+                        if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
+                        && Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
+                        // for existential projection, substs are shifted over by 1
+                        && let ty::Tuple(args) = proj.substs.type_at(0).kind()
+                        {
+                            Some((
+                                DefIdOrName::Name("trait object"),
+                                pred.rebind(proj.term.ty().unwrap()),
+                                pred.rebind(args.as_slice()),
+                            ))
+                        } else {
+                            None
+                        }
+                    })
+                }
+                ty::Param(param) => {
+                    let generics = self.tcx.generics_of(hir_id.owner.to_def_id());
+                    let name = if generics.count() > param.index as usize
+                        && let def = generics.param_at(param.index as usize, self.tcx)
+                        && matches!(def.kind, ty::GenericParamDefKind::Type { .. })
+                        && def.name == param.name
+                    {
+                        DefIdOrName::DefId(def.def_id)
+                    } else {
+                        DefIdOrName::Name("type parameter")
+                    };
+                    param_env.caller_bounds().iter().find_map(|pred| {
+                        if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
+                        && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
+                        && proj.projection_ty.self_ty() == found
+                        // args tuple will always be substs[1]
+                        && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+                        {
+                            Some((
+                                name,
+                                pred.kind().rebind(proj.term.ty().unwrap()),
+                                pred.kind().rebind(args.as_slice()),
+                            ))
+                        } else {
+                            None
+                        }
+                    })
+                }
+                _ => None,
+            }
+        }) else { return None; };
+
+        let output = self.replace_bound_vars_with_fresh_vars(
+            DUMMY_SP,
+            LateBoundRegionConversionTime::FnCall,
+            output,
+        );
+        let inputs = inputs
+            .skip_binder()
+            .iter()
+            .map(|ty| {
+                self.replace_bound_vars_with_fresh_vars(
+                    DUMMY_SP,
+                    LateBoundRegionConversionTime::FnCall,
+                    inputs.rebind(*ty),
+                )
+            })
+            .collect();
+
+        // We don't want to register any extra obligations, which should be
+        // implied by wf, but also because that would possibly result in
+        // erroneous errors later on.
+        let InferOk { value: output, obligations: _ } =
+            self.at(&ObligationCause::dummy(), param_env).normalize(output);
+
+        if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
+    }
+
     fn suggest_add_reference_to_arg(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -1375,10 +1429,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 =
@@ -1616,8 +1671,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)
@@ -1653,8 +1707,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;
         };
 
@@ -1678,8 +1731,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),
             ..
@@ -1695,7 +1748,7 @@ fn suggest_impl_trait(
                 // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
                 predicates
                     .principal_def_id()
-                    .map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty())
+                    .map_or(true, |def_id| self.tcx.check_is_object_safe(def_id))
             }
             // We only want to suggest `impl Trait` to `dyn Trait`s.
             // For example, `fn foo() -> str` needs to be filtered out.
@@ -1752,7 +1805,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 {
@@ -1890,8 +1943,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
         {
@@ -1925,6 +1977,7 @@ fn report_closure_arg_mismatch(
         expected: ty::PolyTraitRef<'tcx>,
         cause: &ObligationCauseCode<'tcx>,
         found_node: Option<Node<'_>>,
+        param_env: ty::ParamEnv<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         pub(crate) fn build_fn_sig_ty<'tcx>(
             infcx: &InferCtxt<'tcx>,
@@ -1987,7 +2040,7 @@ pub(crate) fn build_fn_sig_ty<'tcx>(
         self.note_conflicting_closure_bounds(cause, &mut err);
 
         if let Some(found_node) = found_node {
-            hint_missing_borrow(span, found, expected, found_node, &mut err);
+            hint_missing_borrow(self, param_env, span, found, expected, found_node, &mut err);
         }
 
         err
@@ -2017,7 +2070,7 @@ fn note_conflicting_closure_bounds(
 
             // Find another predicate whose self-type is equal to the expected self type,
             // but whose substs don't match.
-            let other_pred = std::iter::zip(&predicates.predicates, &predicates.spans)
+            let other_pred = predicates.into_iter()
                 .enumerate()
                 .find(|(other_idx, (pred, _))| match pred.kind().skip_binder() {
                     ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
@@ -2042,7 +2095,7 @@ fn note_conflicting_closure_bounds(
             // If we found one, then it's very likely the cause of the error.
             if let Some((_, (_, other_pred_span))) = other_pred {
                 err.span_note(
-                    *other_pred_span,
+                    other_pred_span,
                     "closure inferred to have a different signature due to this bound",
                 );
             }
@@ -2170,7 +2223,7 @@ fn maybe_note_obligation_cause_for_async_await(
                     );
 
                     match *ty.kind() {
-                        ty::Generator(did, ..) => {
+                        ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, _) => {
                             generator = generator.or(Some(did));
                             outer_generator = Some(did);
                         }
@@ -2200,7 +2253,7 @@ fn maybe_note_obligation_cause_for_async_await(
                     );
 
                     match *ty.kind() {
-                        ty::Generator(did, ..) => {
+                        ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, ..) => {
                             generator = generator.or(Some(did));
                             outer_generator = Some(did);
                         }
@@ -2259,7 +2312,7 @@ fn maybe_note_obligation_cause_for_async_await(
             // generator interior are not generally known, so we
             // want to erase them when comparing (and anyway,
             // `Send` and other bounds are generally unaffected by
-            // the choice of region).  When erasing regions, we
+            // the choice of region). When erasing regions, we
             // also have to erase late-bound regions. This is
             // because the types that appear in the generator
             // interior generally contain "bound regions" to
@@ -2275,7 +2328,7 @@ fn maybe_note_obligation_cause_for_async_await(
         };
 
         // Get the typeck results from the infcx if the generator is the function we are currently
-        // type-checking; otherwise, get them by performing a query.  This is needed to avoid
+        // type-checking; otherwise, get them by performing a query. This is needed to avoid
         // cycles. If we can't use resolved types because the generator comes from another crate,
         // we still provide a targeted error but without all the relevant spans.
         let generator_data = match &self.typeck_results {
@@ -2289,6 +2342,11 @@ fn maybe_note_obligation_cause_for_async_await(
             _ => return false,
         };
 
+        let generator_within_in_progress_typeck = match &self.typeck_results {
+            Some(t) => t.hir_owner.to_def_id() == generator_did_root,
+            _ => false,
+        };
+
         let mut interior_or_upvar_span = None;
 
         let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches);
@@ -2308,6 +2366,35 @@ fn maybe_note_obligation_cause_for_async_await(
                 *span,
                 Some((*scope_span, *yield_span, *expr, from_awaited_ty)),
             ));
+
+            if interior_or_upvar_span.is_none() && generator_data.is_foreign() {
+                interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span, None));
+            }
+        } else if self.tcx.sess.opts.unstable_opts.drop_tracking_mir
+            // Avoid disclosing internal information to downstream crates.
+            && generator_did.is_local()
+            // Try to avoid cycles.
+            && !generator_within_in_progress_typeck
+        {
+            let generator_info = &self.tcx.mir_generator_witnesses(generator_did);
+            debug!(?generator_info);
+
+            'find_source: for (variant, source_info) in
+                generator_info.variant_fields.iter().zip(&generator_info.variant_source_info)
+            {
+                debug!(?variant);
+                for &local in variant {
+                    let decl = &generator_info.field_tys[local];
+                    debug!(?decl);
+                    if ty_matches(ty::Binder::dummy(decl.ty)) && !decl.ignore_for_traits {
+                        interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(
+                            decl.source_info.span,
+                            Some((None, source_info.span, None, from_awaited_ty)),
+                        ));
+                        break 'find_source;
+                    }
+                }
+            }
         }
 
         if interior_or_upvar_span.is_none() {
@@ -2956,6 +3043,20 @@ fn note_obligation_cause_code<T>(
                                 }
                                 err.note(msg.trim_end_matches(", "))
                             }
+                            ty::GeneratorWitnessMIR(def_id, substs) => {
+                                use std::fmt::Write;
+
+                                // FIXME: this is kind of an unusual format for rustc, can we make it more clear?
+                                // Maybe we should just remove this note altogether?
+                                // FIXME: only print types which don't meet the trait requirement
+                                let mut msg =
+                                    "required because it captures the following types: ".to_owned();
+                                for bty in tcx.generator_hidden_types(*def_id) {
+                                    let ty = bty.subst(tcx, substs);
+                                    write!(msg, "`{}`, ", ty).unwrap();
+                                }
+                                err.note(msg.trim_end_matches(", "))
+                            }
                             ty::Generator(def_id, _, _) => {
                                 let sp = self.tcx.def_span(def_id);
 
@@ -3228,12 +3329,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);
@@ -3672,9 +3768,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`.
@@ -3694,6 +3795,8 @@ fn probe_assoc_types_at_expr(
 
 /// Add a hint to add a missing borrow or remove an unnecessary one.
 fn hint_missing_borrow<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     span: Span,
     found: Ty<'tcx>,
     expected: Ty<'tcx>,
@@ -3701,13 +3804,13 @@ fn hint_missing_borrow<'tcx>(
     err: &mut Diagnostic,
 ) {
     let found_args = match found.kind() {
-        ty::FnPtr(f) => f.inputs().skip_binder().iter(),
+        ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
         kind => {
             span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
         }
     };
     let expected_args = match expected.kind() {
-        ty::FnPtr(f) => f.inputs().skip_binder().iter(),
+        ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
         kind => {
             span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
         }
@@ -3716,14 +3819,14 @@ fn hint_missing_borrow<'tcx>(
     // This could be a variant constructor, for example.
     let Some(fn_decl) = found_node.fn_decl() else { return; };
 
-    let arg_spans = fn_decl.inputs.iter().map(|ty| ty.span);
+    let args = fn_decl.inputs.iter().map(|ty| ty);
 
-    fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
-        let mut refs = 0;
+    fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
+        let mut refs = vec![];
 
-        while let ty::Ref(_, new_ty, _) = ty.kind() {
+        while let ty::Ref(_, new_ty, mutbl) = ty.kind() {
             ty = *new_ty;
-            refs += 1;
+            refs.push(*mutbl);
         }
 
         (ty, refs)
@@ -3732,21 +3835,44 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
     let mut to_borrow = Vec::new();
     let mut remove_borrow = Vec::new();
 
-    for ((found_arg, expected_arg), arg_span) in found_args.zip(expected_args).zip(arg_spans) {
+    for ((found_arg, expected_arg), arg) in found_args.zip(expected_args).zip(args) {
         let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg);
         let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
 
-        if found_ty == expected_ty {
-            if found_refs < expected_refs {
-                to_borrow.push((arg_span, expected_arg.to_string()));
-            } else if found_refs > expected_refs {
-                remove_borrow.push((arg_span, expected_arg.to_string()));
+        if infcx.can_eq(param_env, found_ty, expected_ty).is_ok() {
+            // FIXME: This could handle more exotic cases like mutability mismatches too!
+            if found_refs.len() < expected_refs.len()
+                && found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..]
+            {
+                to_borrow.push((
+                    arg.span.shrink_to_lo(),
+                    expected_refs[..expected_refs.len() - found_refs.len()]
+                        .iter()
+                        .map(|mutbl| format!("&{}", mutbl.prefix_str()))
+                        .collect::<Vec<_>>()
+                        .join(""),
+                ));
+            } else if found_refs.len() > expected_refs.len() {
+                let mut span = arg.span.shrink_to_lo();
+                let mut left = found_refs.len() - expected_refs.len();
+                let mut ty = arg;
+                while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 {
+                    span = span.with_hi(mut_ty.ty.span.lo());
+                    ty = mut_ty.ty;
+                    left -= 1;
+                }
+                let sugg = if left == 0 {
+                    (span, String::new())
+                } else {
+                    (arg.span, expected_arg.to_string())
+                };
+                remove_borrow.push(sugg);
             }
         }
     }
 
     if !to_borrow.is_empty() {
-        err.multipart_suggestion(
+        err.multipart_suggestion_verbose(
             "consider borrowing the argument",
             to_borrow,
             Applicability::MaybeIncorrect,
@@ -3754,7 +3880,7 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
     }
 
     if !remove_borrow.is_empty() {
-        err.multipart_suggestion(
+        err.multipart_suggestion_verbose(
             "do not borrow the argument",
             remove_borrow,
             Applicability::MaybeIncorrect,
index 76a755ed9e09d4a1da7070064fba845301c5d12a..18d30771035fdbcebf4bdf961ff9bbccd2993ed1 100644 (file)
@@ -1,5 +1,4 @@
 use crate::infer::{InferCtxt, TyOrConstInferVar};
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::obligation_forest::ProcessResult;
 use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
 use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
@@ -54,8 +53,6 @@ pub struct FulfillmentContext<'tcx> {
     // fulfillment context.
     predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
 
-    relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
-
     // Is it OK to register obligations into this infcx inside
     // an infcx snapshot?
     //
@@ -85,19 +82,11 @@ pub struct PendingPredicateObligation<'tcx> {
 impl<'a, 'tcx> FulfillmentContext<'tcx> {
     /// Creates a new fulfillment context.
     pub(super) fn new() -> FulfillmentContext<'tcx> {
-        FulfillmentContext {
-            predicates: ObligationForest::new(),
-            relationships: FxHashMap::default(),
-            usable_in_snapshot: false,
-        }
+        FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: false }
     }
 
     pub(super) fn new_in_snapshot() -> FulfillmentContext<'tcx> {
-        FulfillmentContext {
-            predicates: ObligationForest::new(),
-            relationships: FxHashMap::default(),
-            usable_in_snapshot: true,
-        }
+        FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: true }
     }
 
     /// Attempts to select obligations using `selcx`.
@@ -139,20 +128,11 @@ fn register_predicate_obligation(
 
         assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
 
-        super::relationships::update(self, infcx, &obligation);
-
         self.predicates
             .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
     }
 
-    fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
-        {
-            let errors = self.select_where_possible(infcx);
-            if !errors.is_empty() {
-                return errors;
-            }
-        }
-
+    fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
         self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
     }
 
@@ -161,12 +141,57 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
         self.select(selcx)
     }
 
-    fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
-        self.predicates.map_pending_obligations(|o| o.obligation.clone())
+    fn drain_unstalled_obligations(
+        &mut self,
+        infcx: &InferCtxt<'tcx>,
+    ) -> Vec<PredicateObligation<'tcx>> {
+        let mut processor = DrainProcessor { removed_predicates: Vec::new(), infcx };
+        let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut processor);
+        assert!(outcome.errors.is_empty());
+        return processor.removed_predicates;
+
+        struct DrainProcessor<'a, 'tcx> {
+            infcx: &'a InferCtxt<'tcx>,
+            removed_predicates: Vec<PredicateObligation<'tcx>>,
+        }
+
+        impl<'tcx> ObligationProcessor for DrainProcessor<'_, 'tcx> {
+            type Obligation = PendingPredicateObligation<'tcx>;
+            type Error = !;
+            type OUT = Outcome<Self::Obligation, Self::Error>;
+
+            fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool {
+                pending_obligation
+                    .stalled_on
+                    .iter()
+                    .any(|&var| self.infcx.ty_or_const_infer_var_changed(var))
+            }
+
+            fn process_obligation(
+                &mut self,
+                pending_obligation: &mut PendingPredicateObligation<'tcx>,
+            ) -> ProcessResult<PendingPredicateObligation<'tcx>, !> {
+                assert!(self.needs_process_obligation(pending_obligation));
+                self.removed_predicates.push(pending_obligation.obligation.clone());
+                ProcessResult::Changed(vec![])
+            }
+
+            fn process_backedge<'c, I>(
+                &mut self,
+                cycle: I,
+                _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>,
+            ) -> Result<(), !>
+            where
+                I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>,
+            {
+                self.removed_predicates.extend(cycle.map(|c| c.obligation.clone()));
+                Ok(())
+            }
+        }
     }
 
-    fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
-        &mut self.relationships
+    fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
+        self.predicates.map_pending_obligations(|o| o.obligation.clone())
     }
 }
 
@@ -344,7 +369,7 @@ fn process_obligation(
                 }
 
                 ty::PredicateKind::ObjectSafe(trait_def_id) => {
-                    if !self.selcx.tcx().is_object_safe(trait_def_id) {
+                    if !self.selcx.tcx().check_is_object_safe(trait_def_id) {
                         ProcessResult::Error(CodeSelectionError(Unimplemented))
                     } else {
                         ProcessResult::Changed(vec![])
index b6ded4ce5a3962e0d252dd81b0b226c72017174e..a41a601f2db076a700bdb32b787a202268f2a914 100644 (file)
@@ -1,29 +1,36 @@
 //! Miscellaneous type-system utilities that are too small to deserve their own modules.
 
-use crate::infer::InferCtxtExt as _;
 use crate::traits::{self, ObligationCause};
 
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
+use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
 
-use crate::traits::error_reporting::TypeErrCtxtExt;
+use super::outlives_bounds::InferCtxtExt;
 
-#[derive(Clone)]
 pub enum CopyImplementationError<'tcx> {
-    InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>)>),
+    InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
     NotAnAdt,
     HasDestructor,
 }
 
-pub fn can_type_implement_copy<'tcx>(
+pub enum InfringingFieldsReason<'tcx> {
+    Fulfill(Vec<FulfillmentError<'tcx>>),
+    Regions(Vec<RegionResolutionError<'tcx>>),
+}
+
+/// Checks that the fields of the type (an ADT) all implement copy.
+///
+/// If fields don't implement copy, return an error containing a list of
+/// those violating fields. If it's not an ADT, returns `Err(NotAnAdt)`.
+pub fn type_allowed_to_implement_copy<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     self_type: Ty<'tcx>,
     parent_cause: ObligationCause<'tcx>,
 ) -> Result<(), CopyImplementationError<'tcx>> {
-    // FIXME: (@jroesch) float this code up
-    let infcx = tcx.infer_ctxt().build();
     let (adt, substs) = match self_type.kind() {
         // These types used to have a builtin impl.
         // Now libcore provides that impl.
@@ -42,42 +49,82 @@ pub fn can_type_implement_copy<'tcx>(
         _ => return Err(CopyImplementationError::NotAnAdt),
     };
 
+    let copy_def_id = tcx.require_lang_item(hir::LangItem::Copy, Some(parent_cause.span));
+
     let mut infringing = Vec::new();
     for variant in adt.variants() {
         for field in &variant.fields {
-            let ty = field.ty(tcx, substs);
-            if ty.references_error() {
+            // Do this per-field to get better error messages.
+            let infcx = tcx.infer_ctxt().build();
+            let ocx = traits::ObligationCtxt::new(&infcx);
+
+            let unnormalized_ty = field.ty(tcx, substs);
+            if unnormalized_ty.references_error() {
                 continue;
             }
-            let span = tcx.def_span(field.did);
+
+            let field_span = tcx.def_span(field.did);
+            let field_ty_span = match tcx.hir().get_if_local(field.did) {
+                Some(hir::Node::Field(field_def)) => field_def.ty.span,
+                _ => field_span,
+            };
+
             // FIXME(compiler-errors): This gives us better spans for bad
             // projection types like in issue-50480.
             // If the ADT has substs, point to the cause we are given.
             // If it does not, then this field probably doesn't normalize
             // to begin with, and point to the bad field's span instead.
-            let cause = if field
+            let normalization_cause = if field
                 .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
                 .has_non_region_param()
             {
                 parent_cause.clone()
             } else {
-                ObligationCause::dummy_with_span(span)
-            };
-            match traits::fully_normalize(&infcx, cause, param_env, ty) {
-                Ok(ty) => {
-                    if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
-                        infringing.push((field, ty));
-                    }
-                }
-                Err(errors) => {
-                    infcx.err_ctxt().report_fulfillment_errors(&errors, None);
-                }
+                ObligationCause::dummy_with_span(field_ty_span)
             };
+            let ty = ocx.normalize(&normalization_cause, param_env, unnormalized_ty);
+            let normalization_errors = ocx.select_where_possible();
+            if !normalization_errors.is_empty() {
+                tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking Copy implementation"));
+                continue;
+            }
+
+            ocx.register_bound(
+                ObligationCause::dummy_with_span(field_ty_span),
+                param_env,
+                ty,
+                copy_def_id,
+            );
+            let errors = ocx.select_all_or_error();
+            if !errors.is_empty() {
+                infringing.push((field, ty, InfringingFieldsReason::Fulfill(errors)));
+            }
+
+            // Check regions assuming the self type of the impl is WF
+            let outlives_env = OutlivesEnvironment::with_bounds(
+                param_env,
+                Some(&infcx),
+                infcx.implied_bounds_tys(
+                    param_env,
+                    parent_cause.body_id,
+                    FxIndexSet::from_iter([self_type]),
+                ),
+            );
+            infcx.process_registered_region_obligations(
+                outlives_env.region_bound_pairs(),
+                param_env,
+            );
+            let errors = infcx.resolve_regions(&outlives_env);
+            if !errors.is_empty() {
+                infringing.push((field, ty, InfringingFieldsReason::Regions(errors)));
+            }
         }
     }
+
     if !infringing.is_empty() {
         return Err(CopyImplementationError::InfrigingFields(infringing));
     }
+
     if adt.has_dtor(tcx) {
         return Err(CopyImplementationError::HasDestructor);
     }
index 37b40a2f75adc108a77765070c011073a69da460..83458017e00f00b7cabdc6871aedbdf492d0f130 100644 (file)
@@ -14,7 +14,6 @@
 pub mod outlives_bounds;
 mod project;
 pub mod query;
-pub(crate) mod relationships;
 mod select;
 mod specialize;
 mod structural_match;
 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;
@@ -115,14 +113,12 @@ pub fn predicates_for_generics<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     generic_bounds: ty::InstantiatedPredicates<'tcx>,
 ) -> impl Iterator<Item = PredicateObligation<'tcx>> {
-    std::iter::zip(generic_bounds.predicates, generic_bounds.spans).enumerate().map(
-        move |(idx, (predicate, span))| Obligation {
-            cause: cause(idx, span),
-            recursion_depth: 0,
-            param_env,
-            predicate,
-        },
-    )
+    generic_bounds.into_iter().enumerate().map(move |(idx, (predicate, span))| Obligation {
+        cause: cause(idx, span),
+        recursion_depth: 0,
+        param_env,
+        predicate,
+    })
 }
 
 /// Determines whether the type `ty` is known to meet `bound` and
@@ -154,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),
     };
@@ -169,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 => {
@@ -308,7 +302,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     // the `TypeOutlives` predicates first inside the unnormalized parameter environment, and
     // then we normalize the `TypeOutlives` bounds inside the normalized parameter environment.
     //
-    // This works fairly well because trait matching  does not actually care about param-env
+    // This works fairly well because trait matching does not actually care about param-env
     // TypeOutlives predicates - these are normally used by regionck.
     let outlives_predicates: Vec<_> = predicates
         .drain_filter(|predicate| {
@@ -495,7 +489,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 && let param_def_id = self.generics.type_param(param, self.tcx).def_id
                 && self.tcx.parent(param_def_id) == self.trait_item_def_id
             {
-                return ControlFlow::BREAK;
+                return ControlFlow::Break(());
             }
             t.super_visit_with(self)
         }
@@ -504,7 +498,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                 && let param_def_id = self.generics.region_param(&param, self.tcx).def_id
                 && self.tcx.parent(param_def_id) == self.trait_item_def_id
             {
-                return ControlFlow::BREAK;
+                return ControlFlow::Break(());
             }
             r.super_visit_with(self)
         }
@@ -513,7 +507,7 @@ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
                 && let param_def_id = self.generics.const_param(&param, self.tcx).def_id
                 && self.tcx.parent(param_def_id) == self.trait_item_def_id
             {
-                return ControlFlow::BREAK;
+                return ControlFlow::Break(());
             }
             ct.super_visit_with(self)
         }
@@ -521,8 +515,10 @@ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
 
     let generics = tcx.generics_of(trait_item_def_id);
     let predicates = tcx.predicates_of(trait_item_def_id);
-    let impl_trait_ref =
-        tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait");
+    let impl_trait_ref = tcx
+        .impl_trait_ref(impl_def_id)
+        .expect("expected impl to correspond to trait")
+        .subst_identity();
     let param_env = tcx.param_env(impl_def_id);
 
     let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id };
index 8b1ced78f4e8a06fe4a69ed1d0a4f49c8e043935..565cfca9090e19c2c5e41d7d24fd0eb874661733 100644 (file)
@@ -62,6 +62,37 @@ fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [Object
     )
 }
 
+fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
+    let violations = tcx.object_safety_violations(trait_def_id);
+
+    if violations.is_empty() {
+        return true;
+    }
+
+    // If the trait contains any other violations, then let the error reporting path
+    // report it instead of emitting a warning here.
+    if violations.iter().all(|violation| {
+        matches!(
+            violation,
+            ObjectSafetyViolation::Method(_, MethodViolationCode::WhereClauseReferencesSelf, _)
+        )
+    }) {
+        for violation in violations {
+            if let ObjectSafetyViolation::Method(
+                _,
+                MethodViolationCode::WhereClauseReferencesSelf,
+                span,
+            ) = violation
+            {
+                lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation);
+            }
+        }
+        return true;
+    }
+
+    false
+}
+
 /// We say a method is *vtable safe* if it can be invoked on a trait
 /// object. Note that object-safe traits can have some
 /// non-vtable-safe methods, so long as they require `Self: Sized` or
@@ -93,19 +124,6 @@ fn object_safety_violations_for_trait(
             object_safety_violation_for_method(tcx, trait_def_id, &item)
                 .map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span))
         })
-        .filter(|violation| {
-            if let ObjectSafetyViolation::Method(
-                _,
-                MethodViolationCode::WhereClauseReferencesSelf,
-                span,
-            ) = violation
-            {
-                lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation);
-                false
-            } else {
-                true
-            }
-        })
         .collect();
 
     // Check the trait itself.
@@ -395,7 +413,7 @@ fn virtual_call_violation_for_method<'tcx>(
     trait_def_id: DefId,
     method: &ty::AssocItem,
 ) -> Option<MethodViolationCode> {
-    let sig = tcx.fn_sig(method.def_id);
+    let sig = tcx.fn_sig(method.def_id).subst_identity();
 
     // The method's first parameter must be named `self`
     if !method.fn_has_self_parameter {
@@ -783,16 +801,16 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             match t.kind() {
                 ty::Param(_) => {
                     if t == self.tcx.types.self_param {
-                        ControlFlow::BREAK
+                        ControlFlow::Break(())
                     } else {
-                        ControlFlow::CONTINUE
+                        ControlFlow::Continue(())
                     }
                 }
                 ty::Alias(ty::Projection, ref data)
                     if self.tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder =>
                 {
                     // We'll deny these later in their own pass
-                    ControlFlow::CONTINUE
+                    ControlFlow::Continue(())
                 }
                 ty::Alias(ty::Projection, ref data) => {
                     // This is a projected type `<Foo as SomeTrait>::X`.
@@ -809,7 +827,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                     // SomeTrait` is in fact a supertrait of the
                     // current trait. In that case, this type is
                     // legal, because the type `X` will be specified
-                    // in the object type.  Note that we can just use
+                    // in the object type. Note that we can just use
                     // direct equality here because all of these types
                     // are part of the formal parameter listing, and
                     // hence there should be no inference variables.
@@ -820,7 +838,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                         .contains(&data.trait_ref(self.tcx).def_id);
 
                     if is_supertrait_of_current_trait {
-                        ControlFlow::CONTINUE // do not walk contained types, do not report error, do collect $200
+                        ControlFlow::Continue(()) // do not walk contained types, do not report error, do collect $200
                     } else {
                         t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error
                     }
@@ -866,5 +884,6 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>(
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
-    *providers = ty::query::Providers { object_safety_violations, ..*providers };
+    *providers =
+        ty::query::Providers { object_safety_violations, check_is_object_safe, ..*providers };
 }
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 81966f3fcb231791b5cc098dab611e9b81fde698..a11c5e819695296e429657dd82234c44c827c103 100644 (file)
@@ -148,7 +148,7 @@ fn push_candidate(&mut self, candidate: ProjectionCandidate<'tcx>) -> bool {
                 }
 
                 // Prefer where-clauses. As in select, if there are multiple
-                // candidates, we prefer where-clause candidates over impls.  This
+                // candidates, we prefer where-clause candidates over impls. This
                 // may seem a bit surprising, since impls are the source of
                 // "truth" in some sense, but in fact some of the impls that SEEM
                 // applicable are not, because of nested obligations. Where
@@ -1034,7 +1034,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
         }
         Err(ProjectionCacheEntry::InProgress) => {
             // Under lazy normalization, this can arise when
-            // bootstrapping.  That is, imagine an environment with a
+            // bootstrapping. That is, imagine an environment with a
             // where-clause like `A::B == u32`. Now, if we are asked
             // to normalize `A::B`, we will want to check the
             // where-clauses in scope. So we will try to unify `A::B`
@@ -1375,7 +1375,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
     // Check whether the self-type is itself a projection.
     // If so, extract what we know from the trait and try to come up with a good answer.
     let bounds = match *obligation.predicate.self_ty().kind() {
-        ty::Alias(_, ref data) => tcx.bound_item_bounds(data.def_id).subst(tcx, data.substs),
+        ty::Alias(_, ref data) => tcx.item_bounds(data.def_id).subst(tcx, data.substs),
         ty::Infer(ty::TyVar(_)) => {
             // If the self-type is an inference variable, then it MAY wind up
             // being a projected type, so induce an ambiguity.
@@ -1605,6 +1605,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         | ty::Closure(..)
                         | ty::Generator(..)
                         | ty::GeneratorWitness(..)
+                        | ty::GeneratorWitnessMIR(..)
                         | ty::Never
                         | ty::Tuple(..)
                         // Integers and floats always have `u8` as their discriminant.
@@ -1654,6 +1655,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         | ty::Closure(..)
                         | ty::Generator(..)
                         | ty::GeneratorWitness(..)
+                        | ty::GeneratorWitnessMIR(..)
                         | ty::Never
                         // Extern types have unit metadata, according to RFC 2850
                         | ty::Foreign(_)
@@ -2259,25 +2261,23 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
         tcx.predicates_of(impl_fn_def_id).instantiate(tcx, impl_fn_substs),
         &mut obligations,
     );
-    obligations.extend(std::iter::zip(predicates.predicates, predicates.spans).map(
-        |(pred, span)| {
-            Obligation::with_depth(
-                tcx,
-                ObligationCause::new(
-                    obligation.cause.span,
-                    obligation.cause.body_id,
-                    if span.is_dummy() {
-                        super::ItemObligation(impl_fn_def_id)
-                    } else {
-                        super::BindingObligation(impl_fn_def_id, span)
-                    },
-                ),
-                obligation.recursion_depth + 1,
-                obligation.param_env,
-                pred,
-            )
-        },
-    ));
+    obligations.extend(predicates.into_iter().map(|(pred, span)| {
+        Obligation::with_depth(
+            tcx,
+            ObligationCause::new(
+                obligation.cause.span,
+                obligation.cause.body_id,
+                if span.is_dummy() {
+                    super::ItemObligation(impl_fn_def_id)
+                } else {
+                    super::BindingObligation(impl_fn_def_id, span)
+                },
+            ),
+            obligation.recursion_depth + 1,
+            obligation.param_env,
+            pred,
+        )
+    }));
 
     let ty = normalize_with_depth_to(
         selcx,
@@ -2303,10 +2303,10 @@ fn assoc_ty_own_obligations<'cx, 'tcx>(
     nested: &mut Vec<PredicateObligation<'tcx>>,
 ) {
     let tcx = selcx.tcx();
-    let own = tcx
+    let predicates = tcx
         .predicates_of(obligation.predicate.def_id)
         .instantiate_own(tcx, obligation.predicate.substs);
-    for (predicate, span) in std::iter::zip(own.predicates, own.spans) {
+    for (predicate, span) in predicates {
         let normalized = normalize_with_depth_to(
             selcx,
             obligation.param_env,
index 0f21813bc40ae1a85dfd1185f7199ecd2eec708a..455b53bfb7d8fa351b09487b74f46010f3765780 100644 (file)
@@ -31,6 +31,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         | ty::FnPtr(_)
         | ty::Char
         | ty::GeneratorWitness(..)
+        | ty::GeneratorWitnessMIR(..)
         | ty::RawPtr(_)
         | ty::Ref(..)
         | ty::Str
index 09b58894d3040df0e09649406a5633b1b150235b..f183248f2d08b0474e6ef47b7b3ced870c95d53a 100644 (file)
@@ -1,7 +1,9 @@
 use rustc_middle::ty;
+use rustc_session::config::TraitSolver;
 
 use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::InferCtxt;
+use crate::solve::{Certainty, Goal, InferCtxtEvalExt, MaybeCause};
 use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext};
 
 pub trait InferCtxtExt<'tcx> {
@@ -77,12 +79,38 @@ fn evaluate_obligation(
             _ => obligation.param_env.without_const(),
         };
 
-        let c_pred = self
-            .canonicalize_query_keep_static(param_env.and(obligation.predicate), &mut _orig_values);
-        // Run canonical query. If overflow occurs, rerun from scratch but this time
-        // in standard trait query mode so that overflow is handled appropriately
-        // within `SelectionContext`.
-        self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
+        if self.tcx.sess.opts.unstable_opts.trait_solver != TraitSolver::Next {
+            let c_pred = self.canonicalize_query_keep_static(
+                param_env.and(obligation.predicate),
+                &mut _orig_values,
+            );
+            self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
+        } else {
+            self.probe(|snapshot| {
+                if let Ok((_, certainty)) =
+                    self.evaluate_root_goal(Goal::new(self.tcx, param_env, obligation.predicate))
+                {
+                    match certainty {
+                        Certainty::Yes => {
+                            if self.opaque_types_added_in_snapshot(snapshot) {
+                                Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes)
+                            } else if self.region_constraints_added_in_snapshot(snapshot).is_some()
+                            {
+                                Ok(EvaluationResult::EvaluatedToOkModuloRegions)
+                            } else {
+                                Ok(EvaluationResult::EvaluatedToOk)
+                            }
+                        }
+                        Certainty::Maybe(MaybeCause::Ambiguity) => {
+                            Ok(EvaluationResult::EvaluatedToAmbig)
+                        }
+                        Certainty::Maybe(MaybeCause::Overflow) => Err(OverflowError::Canonical),
+                    }
+                } else {
+                    Ok(EvaluationResult::EvaluatedToErr)
+                }
+            })
+        }
     }
 
     // Helper function that canonicalizes and runs the query. If an
@@ -92,6 +120,9 @@ fn evaluate_obligation_no_overflow(
         &self,
         obligation: &PredicateObligation<'tcx>,
     ) -> EvaluationResult {
+        // Run canonical query. If overflow occurs, rerun from scratch but this time
+        // in standard trait query mode so that overflow is handled appropriately
+        // within `SelectionContext`.
         match self.evaluate_obligation(obligation) {
             Ok(result) => result,
             Err(OverflowError::Canonical) => {
index c6ef13e185b2d7526e6870397a3932e451e6a49c..1b2533a5cf649ce303f556de21e725d5b64f107a 100644 (file)
@@ -133,7 +133,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 .escaping
                 .max(t.outer_exclusive_binder().as_usize() - self.outer_index.as_usize());
         }
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 
     #[inline]
@@ -145,7 +145,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
             _ => {}
         }
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 
     fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -153,7 +153,7 @@ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
                 self.escaping =
                     self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
-                ControlFlow::CONTINUE
+                ControlFlow::Continue(())
             }
             _ => ct.super_visit_with(self),
         }
@@ -201,7 +201,7 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         // wait to fold the substs.
 
         // Wrap this in a closure so we don't accidentally return from the outer function
-        let res = (|| match *ty.kind() {
+        let res = match *ty.kind() {
             // This is really important. While we *can* handle this, this has
             // severe performance implications for large opaque types with
             // late-bound regions. See `issue-88862` benchmark.
@@ -210,18 +210,22 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
             {
                 // Only normalize `impl Trait` outside of type inference, usually in codegen.
                 match self.param_env.reveal() {
-                    Reveal::UserFacing => ty.try_super_fold_with(self),
+                    Reveal::UserFacing => ty.try_super_fold_with(self)?,
 
                     Reveal::All => {
                         let substs = substs.try_fold_with(self)?;
                         let recursion_limit = self.tcx().recursion_limit();
                         if !recursion_limit.value_within_limit(self.anon_depth) {
-                            self.infcx.err_ctxt().report_overflow_error(
-                                &ty,
-                                self.cause.span,
-                                true,
-                                |_| {},
-                            );
+                            // A closure or generator may have itself as in its upvars.
+                            // This should be checked handled by the recursion check for opaque
+                            // types, but we may end up here before that check can happen.
+                            // In that case, we delay a bug to mark the trip, and continue without
+                            // revealing the opaque.
+                            self.infcx
+                                .err_ctxt()
+                                .build_overflow_error(&ty, self.cause.span, true)
+                                .delay_as_bug();
+                            return ty.try_super_fold_with(self);
                         }
 
                         let generic_ty = self.tcx().bound_type_of(def_id);
@@ -239,7 +243,7 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
                         }
                         let folded_ty = ensure_sufficient_stack(|| self.try_fold_ty(concrete_ty));
                         self.anon_depth -= 1;
-                        folded_ty
+                        folded_ty?
                     }
                 }
             }
@@ -287,9 +291,9 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
                 // `tcx.normalize_projection_ty` may normalize to a type that still has
                 // unevaluated consts, so keep normalizing here if that's the case.
                 if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
-                    Ok(res.try_super_fold_with(self)?)
+                    res.try_super_fold_with(self)?
                 } else {
-                    Ok(res)
+                    res
                 }
             }
 
@@ -344,14 +348,14 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
                 // `tcx.normalize_projection_ty` may normalize to a type that still has
                 // unevaluated consts, so keep normalizing here if that's the case.
                 if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
-                    Ok(res.try_super_fold_with(self)?)
+                    res.try_super_fold_with(self)?
                 } else {
-                    Ok(res)
+                    res
                 }
             }
 
-            _ => ty.try_super_fold_with(self),
-        })()?;
+            _ => ty.try_super_fold_with(self)?,
+        };
 
         self.cache.insert(ty, res);
         Ok(res)
diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs
deleted file mode 100644 (file)
index 34b5fc4..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-use crate::infer::InferCtxt;
-use crate::traits::query::evaluate_obligation::InferCtxtExt;
-use crate::traits::PredicateObligation;
-use rustc_infer::traits::TraitEngine;
-use rustc_middle::ty;
-
-pub(crate) fn update<'tcx, T>(
-    engine: &mut T,
-    infcx: &InferCtxt<'tcx>,
-    obligation: &PredicateObligation<'tcx>,
-) where
-    T: TraitEngine<'tcx>,
-{
-    // (*) binder skipped
-    if let ty::PredicateKind::Clause(ty::Clause::Trait(tpred)) = obligation.predicate.kind().skip_binder()
-        && let Some(ty) = infcx.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| infcx.root_var(t))
-        && infcx.tcx.lang_items().sized_trait().map_or(false, |st| st != tpred.trait_ref.def_id)
-    {
-        let new_self_ty = infcx.tcx.types.unit;
-
-        // Then construct a new obligation with Self = () added
-        // to the ParamEnv, and see if it holds.
-        let o = obligation.with(infcx.tcx,
-            obligation
-                .predicate
-                .kind()
-                .rebind(
-                    // (*) binder moved here
-                    ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_ty(infcx.tcx, new_self_ty)))
-                ),
-        );
-        // Don't report overflow errors. Otherwise equivalent to may_hold.
-        if let Ok(result) = infcx.probe(|_| infcx.evaluate_obligation(&o)) && result.may_apply() {
-            engine.relationships().entry(ty).or_default().self_in_trait = true;
-        }
-    }
-
-    if let ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) =
-        obligation.predicate.kind().skip_binder()
-    {
-        // If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
-        // we need to make it into one.
-        if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
-            debug!("relationship: {:?}.output = true", vid);
-            engine.relationships().entry(vid).or_default().output = true;
-        }
-    }
-}
index 8c291d1595d960a1c5bcc473127ac6044c022e41..7b7abcf552ab7da31b513f5346fbad37e814113a 100644 (file)
@@ -174,8 +174,8 @@ fn assemble_candidates_from_caller_bounds<'o>(
             .param_env
             .caller_bounds()
             .iter()
-            .filter_map(|p| p.to_opt_poly_trait_pred())
-            .filter(|p| !p.references_error());
+            .filter(|p| !p.references_error())
+            .filter_map(|p| p.to_opt_poly_trait_pred());
 
         // Micro-optimization: filter out predicates relating to different traits.
         let matching_bounds =
@@ -357,7 +357,7 @@ fn assemble_candidates_from_impls(
                 // Before we create the substitutions and everything, first
                 // consider a "quick reject". This avoids creating more types
                 // and so forth that we need to.
-                let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap();
+                let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
                 if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) {
                     return;
                 }
@@ -398,7 +398,7 @@ fn assemble_candidates_from_auto_impls(
                 }
                 ty::Param(..) | ty::Alias(ty::Projection, ..) => {
                     // In these cases, we don't know what the actual
-                    // type is.  Therefore, we cannot break it down
+                    // type is. Therefore, we cannot break it down
                     // into its constituent types. So we don't
                     // consider the `..` impl but instead just add no
                     // candidates: this means that typeck will only
@@ -466,7 +466,7 @@ fn assemble_candidates_from_object_ty(
                     if let Some(principal) = data.principal() {
                         if !self.infcx.tcx.features().object_safe_for_dispatch {
                             principal.with_self_ty(self.tcx(), self_ty)
-                        } else if self.tcx().is_object_safe(principal.def_id()) {
+                        } else if self.tcx().check_is_object_safe(principal.def_id()) {
                             principal.with_self_ty(self.tcx(), self_ty)
                         } else {
                             return;
@@ -765,7 +765,8 @@ fn assemble_const_destruct_candidates(
             | ty::Closure(..)
             | ty::Generator(..)
             | ty::Tuple(_)
-            | ty::GeneratorWitness(_) => {
+            | ty::GeneratorWitness(_)
+            | ty::GeneratorWitnessMIR(..) => {
                 // These are built-in, and cannot have a custom `impl const Destruct`.
                 candidates.vec.push(ConstDestructCandidate(None));
             }
@@ -826,6 +827,7 @@ fn assemble_candidate_for_tuple(
             | ty::Closure(_, _)
             | ty::Generator(_, _, _)
             | ty::GeneratorWitness(_)
+            | ty::GeneratorWitnessMIR(..)
             | ty::Never
             | ty::Alias(..)
             | ty::Param(_)
index a41d10f104358ea57f8f6e4cb641e38455b63ad7..9c84bfaad492bce593d072a43b55c36bda4c707d 100644 (file)
@@ -2,7 +2,7 @@
 //!
 //! Confirmation unifies the output type parameters of the trait
 //! with the values found in the obligation, possibly yielding a
-//! type error.  See the [rustc dev guide] for more details.
+//! type error. See the [rustc dev guide] for more details.
 //!
 //! [rustc dev guide]:
 //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
@@ -13,7 +13,7 @@
 use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
 use rustc_middle::ty::{
     self, Binder, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef,
-    ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt,
+    ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeVisitable,
 };
 use rustc_session::config::TraitSolver;
 use rustc_span::def_id::DefId;
@@ -160,8 +160,7 @@ fn confirm_projection_candidate(
             _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
         };
 
-        let candidate_predicate =
-            tcx.bound_item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs);
+        let candidate_predicate = tcx.item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs);
         let candidate = candidate_predicate
             .to_opt_poly_trait_pred()
             .expect("projection candidate is not a trait predicate")
@@ -185,9 +184,8 @@ fn confirm_projection_candidate(
         })?);
 
         if let ty::Alias(ty::Projection, ..) = placeholder_self_ty.kind() {
-            let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates;
-            debug!(?predicates, "projection predicates");
-            for predicate in predicates {
+            let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
+            for (predicate, _) in predicates {
                 let normalized = normalize_with_depth_to(
                     self,
                     obligation.param_env,
@@ -357,8 +355,8 @@ fn vtable_auto_impl(
                 nested,
             );
 
-            // Adds the predicates from the trait.  Note that this contains a `Self: Trait`
-            // predicate as usual.  It won't have any effect since auto traits are coinductive.
+            // Adds the predicates from the trait. Note that this contains a `Self: Trait`
+            // predicate as usual. It won't have any effect since auto traits are coinductive.
             obligations.extend(trait_obligations);
 
             debug!(?obligations, "vtable_auto_impl");
@@ -511,7 +509,7 @@ fn confirm_object_candidate(
             // This maybe belongs in wf, but that can't (doesn't) handle
             // higher-ranked things.
             // Prevent, e.g., `dyn Iterator<Item = str>`.
-            for bound in self.tcx().bound_item_bounds(assoc_type).transpose_iter() {
+            for bound in self.tcx().item_bounds(assoc_type).transpose_iter() {
                 let subst_bound =
                     if defs.count() == 0 {
                         bound.subst(tcx, trait_predicate.trait_ref.substs)
@@ -1011,7 +1009,7 @@ fn confirm_builtin_unsize_candidate(
             // `T` -> `Trait`
             (_, &ty::Dynamic(ref data, r, ty::Dyn)) => {
                 let mut object_dids = data.auto_traits().chain(data.principal_def_id());
-                if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) {
+                if let Some(did) = object_dids.find(|did| !tcx.check_is_object_safe(*did)) {
                     return Err(TraitNotObjectSafe(did));
                 }
 
@@ -1287,6 +1285,14 @@ fn confirm_const_destruct_candidate(
                 ty::GeneratorWitness(tys) => {
                     stack.extend(tcx.erase_late_bound_regions(tys).to_vec());
                 }
+                ty::GeneratorWitnessMIR(def_id, substs) => {
+                    let tcx = self.tcx();
+                    stack.extend(tcx.generator_hidden_types(def_id).map(|bty| {
+                        let ty = bty.subst(tcx, substs);
+                        debug_assert!(!ty.has_late_bound_regions());
+                        ty
+                    }))
+                }
 
                 // If we have a projection type, make sure to normalize it so we replace it
                 // with a fresh infer variable
index 305902af7c8290469f4660d519398536c64e5cfe..b8f5aeee2d593f4386107e3d11b4f9a2144cffa4 100644 (file)
@@ -38,6 +38,8 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::LateBoundRegionConversionTime;
+use rustc_infer::traits::TraitEngine;
+use rustc_infer::traits::TraitEngineExt;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
@@ -47,6 +49,7 @@
 use rustc_middle::ty::SubstsRef;
 use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
 use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_session::config::TraitSolver;
 use rustc_span::symbol::sym;
 
 use std::cell::{Cell, RefCell};
@@ -430,7 +433,7 @@ fn candidate_from_obligation_no_cache<'o>(
         //     impl<T:Clone> Vec<T> { fn push_clone(...) { ... } }
         //
         // and we were to see some code `foo.push_clone()` where `boo`
-        // is a `Vec<Bar>` and `Bar` does not implement `Clone`.  If
+        // is a `Vec<Bar>` and `Bar` does not implement `Clone`. If
         // we were to winnow, we'd wind up with zero candidates.
         // Instead, we select the right impl now but report "`Bar` does
         // not implement `Clone`".
@@ -544,10 +547,14 @@ pub fn evaluate_root_obligation(
         obligation: &PredicateObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
         self.evaluation_probe(|this| {
-            this.evaluate_predicate_recursively(
-                TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
-                obligation.clone(),
-            )
+            if this.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Next {
+                this.evaluate_predicate_recursively(
+                    TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
+                    obligation.clone(),
+                )
+            } else {
+                this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])
+            }
         })
     }
 
@@ -586,18 +593,40 @@ fn evaluate_predicates_recursively<'o, I>(
     where
         I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
     {
-        let mut result = EvaluatedToOk;
-        for obligation in predicates {
-            let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
-            if let EvaluatedToErr = eval {
-                // fast-path - EvaluatedToErr is the top of the lattice,
-                // so we don't need to look on the other predicates.
-                return Ok(EvaluatedToErr);
-            } else {
-                result = cmp::max(result, eval);
+        if self.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Next {
+            let mut result = EvaluatedToOk;
+            for obligation in predicates {
+                let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
+                if let EvaluatedToErr = eval {
+                    // fast-path - EvaluatedToErr is the top of the lattice,
+                    // so we don't need to look on the other predicates.
+                    return Ok(EvaluatedToErr);
+                } else {
+                    result = cmp::max(result, eval);
+                }
             }
+            Ok(result)
+        } else {
+            self.evaluate_predicates_recursively_in_new_solver(predicates)
         }
-        Ok(result)
+    }
+
+    /// Evaluates the predicates using the new solver when `-Ztrait-solver=next` is enabled
+    fn evaluate_predicates_recursively_in_new_solver(
+        &mut self,
+        predicates: impl IntoIterator<Item = PredicateObligation<'tcx>>,
+    ) -> Result<EvaluationResult, OverflowError> {
+        let mut fulfill_cx = crate::solve::FulfillmentCtxt::new();
+        fulfill_cx.register_predicate_obligations(self.infcx, predicates);
+        // True errors
+        if !fulfill_cx.select_where_possible(self.infcx).is_empty() {
+            return Ok(EvaluatedToErr);
+        }
+        if !fulfill_cx.select_all_or_error(self.infcx).is_empty() {
+            return Ok(EvaluatedToAmbig);
+        }
+        // Regions and opaques are handled in the `evaluation_probe` by looking at the snapshot
+        Ok(EvaluatedToOk)
     }
 
     #[instrument(
@@ -768,7 +797,7 @@ fn evaluate_predicate_recursively<'o>(
                 }
 
                 ty::PredicateKind::ObjectSafe(trait_def_id) => {
-                    if self.tcx().is_object_safe(trait_def_id) {
+                    if self.tcx().check_is_object_safe(trait_def_id) {
                         Ok(EvaluatedToOk)
                     } else {
                         Ok(EvaluatedToErr)
@@ -1604,7 +1633,7 @@ fn match_projection_obligation_against_definition_bounds(
                 );
             }
         };
-        let bounds = tcx.bound_item_bounds(def_id).subst(tcx, substs);
+        let bounds = tcx.item_bounds(def_id).subst(tcx, substs);
 
         // The bounds returned by `item_bounds` may contain duplicates after
         // normalization, so try to deduplicate when possible to avoid
@@ -2037,6 +2066,7 @@ fn sized_conditions(
             | ty::Ref(..)
             | ty::Generator(..)
             | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..)
             | ty::Array(..)
             | ty::Closure(..)
             | ty::Never
@@ -2153,6 +2183,16 @@ fn copy_clone_conditions(
                 Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars))
             }
 
+            ty::GeneratorWitnessMIR(def_id, ref substs) => {
+                let hidden_types = bind_generator_hidden_types_above(
+                    self.infcx,
+                    def_id,
+                    substs,
+                    obligation.predicate.bound_vars(),
+                );
+                Where(hidden_types)
+            }
+
             ty::Closure(_, substs) => {
                 // (*) binder moved here
                 let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
@@ -2250,6 +2290,10 @@ fn constituent_types_for_ty(
                 types.map_bound(|types| types.to_vec())
             }
 
+            ty::GeneratorWitnessMIR(def_id, ref substs) => {
+                bind_generator_hidden_types_above(self.infcx, def_id, substs, t.bound_vars())
+            }
+
             // For `PhantomData<T>`, we pass `T`.
             ty::Adt(def, substs) if def.is_phantom_data() => t.rebind(substs.types().collect()),
 
@@ -2324,7 +2368,7 @@ fn collect_predicates_for_types(
     // Matching
     //
     // Matching is a common path used for both evaluation and
-    // confirmation.  It basically unifies types that appear in impls
+    // confirmation. It basically unifies types that appear in impls
     // and traits. This does affect the surrounding environment;
     // therefore, when used during evaluation, match routines must be
     // run inside of a `probe()` so that their side-effects are
@@ -2335,7 +2379,7 @@ fn rematch_impl(
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
     ) -> Normalized<'tcx, SubstsRef<'tcx>> {
-        let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap();
+        let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
         match self.match_impl(impl_def_id, impl_trait_ref, obligation) {
             Ok(substs) => substs,
             Err(()) => {
@@ -2558,12 +2602,11 @@ fn impl_or_trait_obligations(
         // obligation will normalize to `<$0 as Iterator>::Item = $1` and
         // `$1: Copy`, so we must ensure the obligations are emitted in
         // that order.
-        let predicates = tcx.bound_predicates_of(def_id);
-        debug!(?predicates);
-        assert_eq!(predicates.0.parent, None);
-        let mut obligations = Vec::with_capacity(predicates.0.predicates.len());
-        for (predicate, span) in predicates.0.predicates {
-            let span = *span;
+        let predicates = tcx.predicates_of(def_id);
+        assert_eq!(predicates.parent, None);
+        let predicates = predicates.instantiate_own(tcx, substs);
+        let mut obligations = Vec::with_capacity(predicates.len());
+        for (predicate, span) in predicates {
             let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
                 ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
                     derived,
@@ -2576,7 +2619,7 @@ fn impl_or_trait_obligations(
                 param_env,
                 cause.clone(),
                 recursion_depth,
-                predicates.rebind(*predicate).subst(tcx, substs),
+                predicate,
                 &mut obligations,
             );
             obligations.push(Obligation { cause, recursion_depth, param_env, predicate });
@@ -2644,7 +2687,7 @@ fn update_reached_depth(&self, reached_depth: usize) {
 /// In Issue #60010, we found a bug in rustc where it would cache
 /// these intermediate results. This was fixed in #60444 by disabling
 /// *all* caching for things involved in a cycle -- in our example,
-/// that would mean we don't cache that `Bar<T>: Send`.  But this led
+/// that would mean we don't cache that `Bar<T>: Send`. But this led
 /// to large slowdowns.
 ///
 /// Specifically, imagine this scenario, where proving `Baz<T>: Send`
@@ -2670,7 +2713,7 @@ fn update_reached_depth(&self, reached_depth: usize) {
 /// a result at `reached_depth`, so it marks the *current* solution as
 /// provisional as well. If an error is encountered, we toss out any
 /// provisional results added from the subtree that encountered the
-/// error.  When we pop the node at `reached_depth` from the stack, we
+/// error. When we pop the node at `reached_depth` from the stack, we
 /// can commit all the things that remain in the provisional cache.
 struct ProvisionalEvaluationCache<'tcx> {
     /// next "depth first number" to issue -- just a counter
@@ -2781,7 +2824,7 @@ fn insert_provisional(
     }
 
     /// Invoked when the node with dfn `dfn` does not get a successful
-    /// result.  This will clear out any provisional cache entries
+    /// result. This will clear out any provisional cache entries
     /// that were added since `dfn` was created. This is because the
     /// provisional entries are things which must assume that the
     /// things on the stack at the time of their creation succeeded --
@@ -2893,3 +2936,56 @@ pub enum ProjectionMatchesProjection {
     Ambiguous,
     No,
 }
+
+/// Replace all regions inside the generator interior with late bound regions.
+/// Note that each region slot in the types gets a new fresh late bound region, which means that
+/// none of the regions inside relate to any other, even if typeck had previously found constraints
+/// that would cause them to be related.
+#[instrument(level = "trace", skip(infcx), ret)]
+fn bind_generator_hidden_types_above<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    def_id: DefId,
+    substs: ty::SubstsRef<'tcx>,
+    bound_vars: &ty::List<ty::BoundVariableKind>,
+) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> {
+    let tcx = infcx.tcx;
+    let mut seen_tys = FxHashSet::default();
+
+    let considering_regions = infcx.considering_regions;
+
+    let num_bound_variables = bound_vars.len() as u32;
+    let mut counter = num_bound_variables;
+
+    let hidden_types: Vec<_> = tcx
+        .generator_hidden_types(def_id)
+        // Deduplicate tys to avoid repeated work.
+        .filter(|bty| seen_tys.insert(*bty))
+        .map(|bty| {
+            let mut ty = bty.subst(tcx, substs);
+
+            // Only remap erased regions if we use them.
+            if considering_regions {
+                ty = tcx.fold_regions(ty, |mut r, current_depth| {
+                    if let ty::ReErased = r.kind() {
+                        let br = ty::BoundRegion {
+                            var: ty::BoundVar::from_u32(counter),
+                            kind: ty::BrAnon(counter, None),
+                        };
+                        counter += 1;
+                        r = tcx.mk_region(ty::ReLateBound(current_depth, br));
+                    }
+                    r
+                })
+            }
+
+            ty
+        })
+        .collect();
+    if considering_regions {
+        debug_assert!(!hidden_types.has_erased_regions());
+    }
+    let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.iter().chain(
+        (num_bound_variables..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))),
+    ));
+    ty::Binder::bind_with_vars(hidden_types, bound_vars)
+}
index a251a508b48cf1777f4d86e62583066eb8caa0b7..3b796c623c0ab11a771bf7eb990b1433dc607ef5 100644 (file)
@@ -87,7 +87,7 @@ pub fn translate_substs<'tcx>(
         param_env, source_impl, source_substs, target_node
     );
     let source_trait_ref =
-        infcx.tcx.bound_impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs);
+        infcx.tcx.impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs);
 
     // translate the Self and Param parts of the substitution, since those
     // vary across impls
@@ -148,7 +148,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
 
     // create a parameter environment corresponding to a (placeholder) instantiation of impl1
     let penv = tcx.param_env(impl1_def_id);
-    let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
+    let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity();
 
     // Create an infcx, taking the predicates of impl1 as assumptions:
     let infcx = tcx.infer_ctxt().build();
@@ -431,7 +431,7 @@ fn decorate<'tcx>(
 pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
     use std::fmt::Write;
 
-    let trait_ref = tcx.impl_trait_ref(impl_def_id)?;
+    let trait_ref = tcx.impl_trait_ref(impl_def_id)?.subst_identity();
     let mut w = "impl".to_owned();
 
     let substs = InternalSubsts::identity_for_item(tcx, impl_def_id);
index 02b0667774028a37224a926b1d74bb9a92f52b6f..0f9196de4fb197f5974d6b38b437352878ccabf9 100644 (file)
@@ -48,7 +48,7 @@ fn insert(
 impl<'tcx> ChildrenExt<'tcx> for Children {
     /// Insert an impl into this set of children without comparing to any existing impls.
     fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
-        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
         if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
         {
             debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
@@ -63,7 +63,7 @@ fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
     /// an impl with a parent. The impl must be present in the list of
     /// children already.
     fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
-        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
         let vec: &mut Vec<DefId>;
         if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
         {
@@ -181,7 +181,7 @@ fn insert(
             if le && !ge {
                 debug!(
                     "descending as child of TraitRef {:?}",
-                    tcx.impl_trait_ref(possible_sibling).unwrap()
+                    tcx.impl_trait_ref(possible_sibling).unwrap().subst_identity()
                 );
 
                 // The impl specializes `possible_sibling`.
@@ -189,7 +189,7 @@ fn insert(
             } else if ge && !le {
                 debug!(
                     "placing as parent of TraitRef {:?}",
-                    tcx.impl_trait_ref(possible_sibling).unwrap()
+                    tcx.impl_trait_ref(possible_sibling).unwrap().subst_identity()
                 );
 
                 replace_children.push(possible_sibling);
@@ -275,7 +275,8 @@ fn insert(
     ) -> Result<Option<FutureCompatOverlapError<'tcx>>, OverlapError<'tcx>> {
         assert!(impl_def_id.is_local());
 
-        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+        // FIXME: use `EarlyBinder` in `self.children`
+        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
         let trait_def_id = trait_ref.def_id;
 
         debug!(
@@ -388,7 +389,7 @@ pub(crate) fn assoc_def(
     impl_def_id: DefId,
     assoc_def_id: DefId,
 ) -> Result<LeafDef, ErrorGuaranteed> {
-    let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
+    let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
     let trait_def = tcx.trait_def(trait_def_id);
 
     // This function may be called while we are still building the
@@ -417,7 +418,7 @@ pub(crate) fn assoc_def(
     } else {
         // This is saying that neither the trait nor
         // the impl contain a definition for this
-        // associated type.  Normally this situation
+        // associated type. Normally this situation
         // could only arise through a compiler bug --
         // if the user wrote a bad item name, it
         // should have failed in astconv.
index 892a7afd799c73c64ff0a5c6ba5bbf156b68fa9e..69b965f3a389a58ca3ed4c2ce218c3e0cd2431d9 100644 (file)
@@ -101,31 +101,31 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             ty::Closure(..) => {
                 return ControlFlow::Break(ty);
             }
-            ty::Generator(..) | ty::GeneratorWitness(..) => {
+            ty::Generator(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => {
                 return ControlFlow::Break(ty);
             }
             ty::FnDef(..) => {
                 // Types of formals and return in `fn(_) -> _` are also irrelevant;
                 // so we do not recur into them via `super_visit_with`
-                return ControlFlow::CONTINUE;
+                return ControlFlow::Continue(());
             }
             ty::Array(_, n)
                 if { n.try_eval_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } =>
             {
                 // rust-lang/rust#62336: ignore type of contents
                 // for empty array.
-                return ControlFlow::CONTINUE;
+                return ControlFlow::Continue(());
             }
             ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => {
                 // These primitive types are always structural match.
                 //
                 // `Never` is kind of special here, but as it is not inhabitable, this should be fine.
-                return ControlFlow::CONTINUE;
+                return ControlFlow::Continue(());
             }
 
             ty::FnPtr(..) => {
                 if !self.adt_const_param {
-                    return ControlFlow::CONTINUE;
+                    return ControlFlow::Continue(());
                 } else {
                     return ControlFlow::Break(ty);
                 }
@@ -147,7 +147,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                     // Even though `NonStructural` does not implement `PartialEq`,
                     // structural equality on `T` does not recur into the raw
                     // pointer. Therefore, one can still use `C` in a pattern.
-                    return ControlFlow::CONTINUE;
+                    return ControlFlow::Continue(());
                 } else {
                     return ControlFlow::Break(ty);
                 }
@@ -155,7 +155,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
 
             ty::Float(_) => {
                 if !self.adt_const_param {
-                    return ControlFlow::CONTINUE;
+                    return ControlFlow::Continue(());
                 } else {
                     return ControlFlow::Break(ty);
                 }
@@ -172,13 +172,13 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 self.tcx.sess.delay_span_bug(self.span, "ty::Error in structural-match check");
                 // We still want to check other types after encountering an error,
                 // as this may still emit relevant errors.
-                return ControlFlow::CONTINUE;
+                return ControlFlow::Continue(());
             }
         };
 
         if !self.seen.insert(adt_def.did()) {
             debug!("Search already seen adt_def: {:?}", adt_def);
-            return ControlFlow::CONTINUE;
+            return ControlFlow::Continue(());
         }
 
         if !self.type_marked_structural(ty) {
index 5ec9c2a24cd448db3534fa5f3a8798cba24a1c64..64daca714c32d1e8b20d6ed3ed8a300727a0bc69 100644 (file)
@@ -261,7 +261,10 @@ fn vtable_entries<'tcx>(
                     // Note that this method could then never be called, so we
                     // do not want to try and codegen it, in that case (see #23435).
                     let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
-                    if impossible_predicates(tcx, predicates.predicates) {
+                    if impossible_predicates(
+                        tcx,
+                        predicates.map(|(predicate, _)| predicate).collect(),
+                    ) {
                         debug!("vtable_entries: predicates do not hold");
                         return VtblEntry::Vacant;
                     }
index fec4047ff49ba4d4a675b7cd97c4bd8d31c1085a..7c5e147a950f19ba225a50d558f876e04ccc4647 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,14 +75,42 @@ 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
+/// 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
 /// if `Bar: Eq`.
 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,
@@ -523,6 +551,7 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                 | ty::Error(_)
                 | ty::Str
                 | ty::GeneratorWitness(..)
+                | ty::GeneratorWitnessMIR(..)
                 | ty::Never
                 | ty::Param(_)
                 | ty::Bound(..)
@@ -654,7 +683,7 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                     // All of the requirements on type parameters
                     // have already been checked for `impl Trait` in
                     // return position. We do need to check type-alias-impl-trait though.
-                    if ty::is_impl_trait_defn(self.tcx, def_id).is_none() {
+                    if self.tcx.is_type_alias_impl_trait(def_id) {
                         let obligations = self.nominal_obligations(def_id, substs);
                         self.out.extend(obligations);
                     }
@@ -736,7 +765,7 @@ fn nominal_obligations_inner(
         trace!("{:#?}", predicates);
         debug_assert_eq!(predicates.predicates.len(), origins.len());
 
-        iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev())
+        iter::zip(predicates, origins.into_iter().rev())
             .map(|((mut pred, span), origin_def_id)| {
                 let code = if span.is_dummy() {
                     traits::ItemObligation(origin_def_id)
index f288eb112582dfeed77719c0ea805d3c2376c17f..84f7e8362081871f9321492d60eaef815efeee43 100644 (file)
@@ -7,7 +7,7 @@
 //! `crate::chalk::lowering` (to lower rustc types into Chalk types).
 
 use rustc_middle::traits::ChalkRustInterner as RustInterner;
-use rustc_middle::ty::{self, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
+use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
 use rustc_target::abi::{Integer, IntegerType};
 
@@ -38,13 +38,12 @@ fn where_clauses_for(
         def_id: DefId,
         bound_vars: SubstsRef<'tcx>,
     ) -> Vec<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
-        let predicates = self.interner.tcx.predicates_defined_on(def_id).predicates;
-        predicates
-            .iter()
-            .map(|(wc, _)| EarlyBinder(*wc).subst(self.interner.tcx, bound_vars))
-            .filter_map(|wc| LowerInto::<
-                    Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>
-                    >::lower_into(wc, self.interner)).collect()
+        self.interner
+            .tcx
+            .predicates_defined_on(def_id)
+            .instantiate_own(self.interner.tcx, bound_vars)
+            .filter_map(|(wc, _)| LowerInto::lower_into(wc, self.interner))
+            .collect()
     }
 
     fn bounds_for<T>(&self, def_id: DefId, bound_vars: SubstsRef<'tcx>) -> Vec<T>
@@ -270,7 +269,7 @@ fn fn_def_datum(
 
         let where_clauses = self.where_clauses_for(def_id, bound_vars);
 
-        let sig = self.interner.tcx.bound_fn_sig(def_id);
+        let sig = self.interner.tcx.fn_sig(def_id);
         let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars(
             self.interner,
             self.interner.tcx,
@@ -309,7 +308,7 @@ fn impl_datum(
         let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
         let binders = binders_for(self.interner, bound_vars);
 
-        let trait_ref = self.interner.tcx.bound_impl_trait_ref(def_id).expect("not an impl");
+        let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl");
         let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars);
 
         let where_clauses = self.where_clauses_for(def_id, bound_vars);
@@ -351,7 +350,7 @@ fn impls_for_trait(
         let all_impls = self.interner.tcx.all_impls(def_id);
         let matched_impls = all_impls.filter(|impl_def_id| {
             use chalk_ir::could_match::CouldMatch;
-            let trait_ref = self.interner.tcx.bound_impl_trait_ref(*impl_def_id).unwrap();
+            let trait_ref = self.interner.tcx.impl_trait_ref(*impl_def_id).unwrap();
             let bound_vars = bound_vars_for_item(self.interner.tcx, *impl_def_id);
 
             let self_ty = trait_ref.map_bound(|t| t.self_ty());
@@ -380,7 +379,7 @@ fn impl_provided_for(
         let trait_def_id = auto_trait_id.0;
         let all_impls = self.interner.tcx.all_impls(trait_def_id);
         for impl_def_id in all_impls {
-            let trait_ref = self.interner.tcx.impl_trait_ref(impl_def_id).unwrap();
+            let trait_ref = self.interner.tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
             let self_ty = trait_ref.self_ty();
             let provides = match (self_ty.kind(), chalk_ty) {
                 (&ty::Adt(impl_adt_def, ..), Adt(id, ..)) => impl_adt_def.did() == id.0.did(),
@@ -581,7 +580,7 @@ fn well_known_trait_id(
     }
 
     fn is_object_safe(&self, trait_id: chalk_ir::TraitId<RustInterner<'tcx>>) -> bool {
-        self.interner.tcx.is_object_safe(trait_id.0)
+        self.interner.tcx.check_is_object_safe(trait_id.0)
     }
 
     fn hidden_opaque_type(
index 9712abb708f2762c61c6c2b0b922e642c681fb83..3a254105162095aae614f679bf85c39eaa2abe62 100644 (file)
@@ -343,6 +343,7 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'
                 substs.lower_into(interner),
             ),
             ty::GeneratorWitness(_) => unimplemented!(),
+            ty::GeneratorWitnessMIR(..) => unimplemented!(),
             ty::Never => chalk_ir::TyKind::Never,
             ty::Tuple(types) => {
                 chalk_ir::TyKind::Tuple(types.len(), types.as_substs().lower_into(interner))
index f76386fa720dfaa6b2e9e5dbe95ba8ccae81ba10..13d83b92689415f84fee9a26f9c96069c1822981 100644 (file)
@@ -8,13 +8,10 @@
 
 use rustc_data_structures::fx::FxHashMap;
 
-use rustc_index::vec::IndexVec;
-
 use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind};
 use rustc_middle::traits::ChalkRustInterner;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::GenericArg;
-use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{self, ParamTy, TyCtxt, TypeFoldable, TypeVisitable};
 
 use rustc_infer::infer::canonical::{
     Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse,
@@ -100,11 +97,13 @@ pub(crate) fn evaluate_goal<'tcx>(
                          binders: chalk_ir::CanonicalVarKinds<_>| {
         use rustc_middle::infer::canonical::CanonicalVarInfo;
 
-        let mut var_values: IndexVec<BoundVar, GenericArg<'tcx>> = IndexVec::new();
         let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params);
-        subst.as_slice(interner).iter().for_each(|p| {
-            var_values.push(p.lower_into(interner).fold_with(&mut reverse_param_substitutor));
-        });
+        let var_values = tcx.mk_substs(
+            subst
+                .as_slice(interner)
+                .iter()
+                .map(|p| p.lower_into(interner).fold_with(&mut reverse_param_substitutor)),
+        );
         let variables: Vec<_> = binders
             .iter(interner)
             .map(|var| {
@@ -159,8 +158,7 @@ pub(crate) fn evaluate_goal<'tcx>(
                             max_universe: ty::UniverseIndex::from_usize(0),
                             variables: obligation.variables,
                             value: QueryResponse {
-                                var_values: CanonicalVarValues { var_values: IndexVec::new() }
-                                    .make_identity(tcx),
+                                var_values: CanonicalVarValues::dummy(),
                                 region_constraints: QueryRegionConstraints::default(),
                                 certainty: Certainty::Ambiguous,
                                 opaque_types: vec![],
index f127ef8343f91e5a262beed9bd805e6a582a237b..6f81d343e0fd85f54a66dc1921a2033116a94962 100644 (file)
@@ -1,10 +1,10 @@
 // This file contains various trait resolution methods used by codegen.
-// They all assume regions can be erased and monomorphic types.  It
+// They all assume regions can be erased and monomorphic types. It
 // seems likely that they should eventually be merged into more
 // general routines.
 
 use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
-use rustc_infer::traits::FulfillmentErrorCode;
+use rustc_infer::traits::{FulfillmentErrorCode, TraitEngineExt as _};
 use rustc_middle::traits::CodegenObligationError;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
index 481b56e111ea0a6d74099f0017f166fa7e5afad2..8b7f8033bfaceb7d7636eb89ab1576f43db2925c 100644 (file)
@@ -164,7 +164,8 @@ fn dtorck_constraint_for_ty<'tcx>(
         | ty::Ref(..)
         | ty::FnDef(..)
         | ty::FnPtr(_)
-        | ty::GeneratorWitness(..) => {
+        | ty::GeneratorWitness(..)
+        | ty::GeneratorWitnessMIR(..) => {
             // these types never have a destructor
         }
 
index 010233d7718c222372d87b976f7d29e0321c6d9d..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
@@ -154,11 +153,8 @@ fn implied_bounds_from_components<'tcx>(
             match component {
                 Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
                 Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
-                Component::Projection(p) => Some(OutlivesBound::RegionSubProjection(sub_region, p)),
-                Component::Opaque(def_id, substs) => {
-                    Some(OutlivesBound::RegionSubOpaque(sub_region, def_id, substs))
-                }
-                Component::EscapingProjection(_) =>
+                Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)),
+                Component::EscapingAlias(_) =>
                 // If the projection has escaping regions, don't
                 // try to infer any implied bounds even for its
                 // free components. This is conservative, because
index aa5c83ac2e6557cd98e40f7d29cbc18db5a99853..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;
@@ -17,7 +18,6 @@
 use rustc_trait_selection::traits::query::{Fallible, NoSolution};
 use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt};
 use std::fmt;
-use std::iter::zip;
 
 pub(crate) fn provide(p: &mut Providers) {
     *p = Providers {
@@ -77,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(())
 }
 
@@ -108,13 +107,11 @@ fn relate_mir_and_user_substs<'tcx>(
     let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
 
     debug!(?instantiated_predicates);
-    for (instantiated_predicate, predicate_span) in
-        zip(instantiated_predicates.predicates, instantiated_predicates.spans)
-    {
+    for (instantiated_predicate, predicate_span) in instantiated_predicates {
         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 =
@@ -129,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 384d03106b1e8c1cc67760bbfdf3345a741bb859..b3b9a67b26e3d23fcfa2ab9153847dc787145560 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(alloc_layout_extra, control_flow_enum, decl_macro, iterator_try_reduce, never_type)]
+#![feature(alloc_layout_extra, decl_macro, iterator_try_reduce, never_type)]
 #![allow(dead_code, unused_variables)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
index dc1dd1bfaf8e7f30ddd14374c59375957472ed3c..1c74aeca5ab1fae38a6e6234c6ad7b40b292078b 100644 (file)
@@ -41,7 +41,7 @@ fn fn_sig_for_fn_abi<'tcx>(
             // We normalize the `fn_sig` again after substituting at a later point.
             let mut sig = match *ty.kind() {
                 ty::FnDef(def_id, substs) => tcx
-                    .bound_fn_sig(def_id)
+                    .fn_sig(def_id)
                     .map_bound(|fn_sig| {
                         tcx.normalize_erasing_regions(tcx.param_env(def_id), fn_sig)
                     })
@@ -108,21 +108,41 @@ fn fn_sig_for_fn_abi<'tcx>(
             // `Generator::resume(...) -> GeneratorState` function in case we
             // have an ordinary generator, or the `Future::poll(...) -> Poll`
             // function in case this is a special generator backing an async construct.
-            let ret_ty = if tcx.generator_is_async(did) {
-                let state_did = tcx.require_lang_item(LangItem::Poll, None);
-                let state_adt_ref = tcx.adt_def(state_did);
-                let state_substs = tcx.intern_substs(&[sig.return_ty.into()]);
-                tcx.mk_adt(state_adt_ref, state_substs)
+            let (resume_ty, ret_ty) = if tcx.generator_is_async(did) {
+                // The signature should be `Future::poll(_, &mut Context<'_>) -> Poll<Output>`
+                let poll_did = tcx.require_lang_item(LangItem::Poll, None);
+                let poll_adt_ref = tcx.adt_def(poll_did);
+                let poll_substs = tcx.intern_substs(&[sig.return_ty.into()]);
+                let ret_ty = tcx.mk_adt(poll_adt_ref, poll_substs);
+
+                // We have to replace the `ResumeTy` that is used for type and borrow checking
+                // with `&mut Context<'_>` which is used in codegen.
+                #[cfg(debug_assertions)]
+                {
+                    if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() {
+                        let expected_adt =
+                            tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
+                        assert_eq!(*resume_ty_adt, expected_adt);
+                    } else {
+                        panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty);
+                    };
+                }
+                let context_mut_ref = tcx.mk_task_context();
+
+                (context_mut_ref, ret_ty)
             } else {
+                // The signature should be `Generator::resume(_, Resume) -> GeneratorState<Yield, Return>`
                 let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
                 let state_adt_ref = tcx.adt_def(state_did);
                 let state_substs = tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]);
-                tcx.mk_adt(state_adt_ref, state_substs)
+                let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
+
+                (sig.resume_ty, ret_ty)
             };
 
             ty::Binder::bind_with_vars(
                 tcx.mk_fn_sig(
-                    [env_ty, sig.resume_ty].iter(),
+                    [env_ty, resume_ty].iter(),
                     &ret_ty,
                     false,
                     hir::Unsafety::Normal,
@@ -219,13 +239,12 @@ fn adjust_for_rust_scalar<'tcx>(
         return;
     }
 
-    // Scalars which have invalid values cannot be undef.
-    if !scalar.is_always_valid(&cx) {
+    if !scalar.is_uninit_valid() {
         attrs.set(ArgAttribute::NoUndef);
     }
 
     // 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);
@@ -246,11 +265,6 @@ fn adjust_for_rust_scalar<'tcx>(
                 PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
             };
 
-            // `Box`, `&T`, and `&mut T` cannot be undef.
-            // Note that this only applies to the value of the pointer itself;
-            // this attribute doesn't make it UB for the pointed-to data to be undef.
-            attrs.set(ArgAttribute::NoUndef);
-
             // The aliasing rules for `Box<T>` are still not decided, but currently we emit
             // `noalias` for it. This can be turned off using an unstable flag.
             // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
@@ -465,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 a9b4e1420ea0db1b5b9cbe5670e8df8c3f1c84d3..a9fbad55dac5540b6230dd669fdee5926cd06302 100644 (file)
@@ -302,13 +302,53 @@ fn expr_is_poly(&mut self, expr: &thir::Expr<'tcx>) -> bool {
         }
 
         match expr.kind {
-            thir::ExprKind::NamedConst { substs, .. } => substs.has_non_region_param(),
+            thir::ExprKind::NamedConst { substs, .. }
+            | thir::ExprKind::ConstBlock { substs, .. } => substs.has_non_region_param(),
             thir::ExprKind::ConstParam { .. } => true,
             thir::ExprKind::Repeat { value, count } => {
                 self.visit_expr(&self.thir()[value]);
                 count.has_non_region_param()
             }
-            _ => false,
+            thir::ExprKind::Scope { .. }
+            | thir::ExprKind::Box { .. }
+            | thir::ExprKind::If { .. }
+            | thir::ExprKind::Call { .. }
+            | thir::ExprKind::Deref { .. }
+            | thir::ExprKind::Binary { .. }
+            | thir::ExprKind::LogicalOp { .. }
+            | thir::ExprKind::Unary { .. }
+            | thir::ExprKind::Cast { .. }
+            | thir::ExprKind::Use { .. }
+            | thir::ExprKind::NeverToAny { .. }
+            | thir::ExprKind::Pointer { .. }
+            | thir::ExprKind::Loop { .. }
+            | thir::ExprKind::Let { .. }
+            | thir::ExprKind::Match { .. }
+            | thir::ExprKind::Block { .. }
+            | thir::ExprKind::Assign { .. }
+            | thir::ExprKind::AssignOp { .. }
+            | thir::ExprKind::Field { .. }
+            | thir::ExprKind::Index { .. }
+            | thir::ExprKind::VarRef { .. }
+            | thir::ExprKind::UpvarRef { .. }
+            | thir::ExprKind::Borrow { .. }
+            | thir::ExprKind::AddressOf { .. }
+            | thir::ExprKind::Break { .. }
+            | thir::ExprKind::Continue { .. }
+            | thir::ExprKind::Return { .. }
+            | thir::ExprKind::Array { .. }
+            | thir::ExprKind::Tuple { .. }
+            | thir::ExprKind::Adt(_)
+            | thir::ExprKind::PlaceTypeAscription { .. }
+            | thir::ExprKind::ValueTypeAscription { .. }
+            | thir::ExprKind::Closure(_)
+            | thir::ExprKind::Literal { .. }
+            | thir::ExprKind::NonHirLiteral { .. }
+            | thir::ExprKind::ZstLiteral { .. }
+            | thir::ExprKind::StaticRef { .. }
+            | thir::ExprKind::InlineAsm(_)
+            | thir::ExprKind::ThreadLocalRef(_)
+            | thir::ExprKind::Yield { .. } => false,
         }
     }
     fn pat_is_poly(&mut self, pat: &thir::Pat<'tcx>) -> bool {
index b7a24a22c53e3d8d3916257116e62f7f3c741ab2..961c04974e508bc6ca69dc8b320a423ab5afb000 100644 (file)
@@ -9,26 +9,28 @@ pub fn provide(providers: &mut ty::query::Providers) {
 fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
     match tcx.def_kind(def_id) {
         DefKind::Fn => {
-            let sig = tcx.fn_sig(def_id);
+            let sig = tcx.fn_sig(def_id).subst_identity();
             let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
             liberated_sig.inputs_and_output
         }
         DefKind::AssocFn => {
-            let sig = tcx.fn_sig(def_id);
+            let sig = tcx.fn_sig(def_id).subst_identity();
             let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
             let mut assumed_wf_types: Vec<_> =
                 tcx.assumed_wf_types(tcx.parent(def_id)).as_slice().into();
             assumed_wf_types.extend(liberated_sig.inputs_and_output);
             tcx.intern_type_list(&assumed_wf_types)
         }
-        DefKind::Impl => match tcx.impl_trait_ref(def_id) {
-            Some(trait_ref) => {
-                let types: Vec<_> = trait_ref.substs.types().collect();
-                tcx.intern_type_list(&types)
+        DefKind::Impl => {
+            match tcx.impl_trait_ref(def_id) {
+                Some(trait_ref) => {
+                    let types: Vec<_> = trait_ref.skip_binder().substs.types().collect();
+                    tcx.intern_type_list(&types)
+                }
+                // Only the impl self type
+                None => tcx.intern_type_list(&[tcx.type_of(def_id)]),
             }
-            // Only the impl self type
-            None => tcx.intern_type_list(&[tcx.type_of(def_id)]),
-        },
+        }
         DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
         DefKind::Mod
         | DefKind::Struct
index 6aa016133ca598926fffa1b2823962b11332da92..378cd5a99ed864ce3bdd23a2fbb20d2216109ac1 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))
         }
@@ -470,7 +470,10 @@ fn layout_of_uncached<'tcx>(
             return Err(LayoutError::Unknown(ty));
         }
 
-        ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => {
+        ty::Placeholder(..)
+        | ty::GeneratorWitness(..)
+        | ty::GeneratorWitnessMIR(..)
+        | ty::Infer(_) => {
             bug!("Layout::compute: unexpected type `{}`", ty)
         }
 
@@ -640,7 +643,7 @@ fn generator_layout<'tcx>(
 
     let promoted_layouts = ineligible_locals
         .iter()
-        .map(|local| subst_field(info.field_tys[local]))
+        .map(|local| subst_field(info.field_tys[local].ty))
         .map(|ty| tcx.mk_maybe_uninit(ty))
         .map(|ty| cx.layout_of(ty));
     let prefix_layouts = substs
@@ -710,7 +713,7 @@ fn generator_layout<'tcx>(
                     Assigned(_) => bug!("assignment does not match variant"),
                     Ineligible(_) => false,
                 })
-                .map(|local| subst_field(info.field_tys[*local]));
+                .map(|local| subst_field(info.field_tys[*local].ty));
 
             let mut variant = univariant_uninterned(
                 cx,
index 7ad5cbc01ccf25293c116f05025bca179b33d0e3..0853de601b04072100213a4f2b9d114242abd44f 100644 (file)
@@ -6,7 +6,6 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(let_chains)]
-#![feature(control_flow_enum)]
 #![feature(never_type)]
 #![feature(box_patterns)]
 #![recursion_limit = "256"]
index 0df060fc5fb71eae719d70216303c22e90f8af17..cd1475391a4d90f5e9c6c0849896986170c6c583 100644 (file)
@@ -109,6 +109,13 @@ fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
 
             for component in components {
                 match *component.kind() {
+                    // The information required to determine whether a generator has drop is
+                    // computed on MIR, while this very method is used to build MIR.
+                    // To avoid cycles, we consider that generators always require drop.
+                    ty::Generator(..) if tcx.sess.opts.unstable_opts.drop_tracking_mir => {
+                        return Some(Err(AlwaysRequiresDrop));
+                    }
+
                     _ if component.is_copy_modulo_regions(tcx, self.param_env) => (),
 
                     ty::Closure(_, substs) => {
index 87923ebbe4bc948502d1fefca6a13935867bf864..89abffebdc68406b887a4b73f54303a3164065ba 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>(
@@ -16,7 +16,13 @@ fn sized_constraint_for_ty<'tcx>(
         Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
         | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![],
 
-        Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | GeneratorWitness(..) => {
+        Str
+        | Dynamic(..)
+        | Slice(_)
+        | Foreign(..)
+        | Error(_)
+        | GeneratorWitness(..)
+        | GeneratorWitnessMIR(..) => {
             // these are never sized - return the target type
             vec![ty]
         }
@@ -208,14 +214,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)
 }
@@ -289,7 +288,7 @@ enum NodeKind {
         // In a trait impl, we assume that the header trait ref and all its
         // constituents are well-formed.
         NodeKind::TraitImpl => {
-            let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
+            let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl").subst_identity();
 
             // FIXME(chalk): this has problems because of late-bound regions
             //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
@@ -306,7 +305,7 @@ enum NodeKind {
         // In an fn, we assume that the arguments and all their constituents are
         // well-formed.
         NodeKind::Fn => {
-            let fn_sig = tcx.fn_sig(def_id);
+            let fn_sig = tcx.fn_sig(def_id).subst_identity();
             let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig);
 
             inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
@@ -360,7 +359,8 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> {
 
     let trait_ref = tcx
         .impl_trait_ref(def_id)
-        .unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id));
+        .unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id))
+        .skip_binder();
 
     debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref);
 
index 44004cb0be1e9dbf9ae4c4e6b850a0fe677d894a..d5de457a82ce98ece71342abaa4d3ff6f0ee2225 100644 (file)
@@ -265,6 +265,9 @@ pub struct TypeFlags: u32 {
 
         /// Does this value have `InferConst::Fresh`?
         const HAS_CT_FRESH                = 1 << 21;
+
+        /// Does this have `Generator` or `GeneratorWitness`?
+        const HAS_TY_GENERATOR            = 1 << 22;
     }
 }
 
index b944cbd698d13598de404d3f6291718cb7259dfe..e7bb30553736c492533962e8f576f1101a43e87b 100644 (file)
@@ -160,6 +160,32 @@ pub enum TyKind<I: Interner> {
     /// ```
     GeneratorWitness(I::BinderListTy),
 
+    /// A type representing the types stored inside a generator.
+    /// This should only appear as part of the `GeneratorSubsts`.
+    ///
+    /// Unlike upvars, the witness can reference lifetimes from
+    /// inside of the generator itself. To deal with them in
+    /// the type of the generator, we convert them to higher ranked
+    /// lifetimes bound by the witness itself.
+    ///
+    /// This variant is only using when `drop_tracking_mir` is set.
+    /// This contains the `DefId` and the `SubstRef` of the generator.
+    /// The actual witness types are computed on MIR by the `mir_generator_witnesses` query.
+    ///
+    /// Looking at the following example, the witness for this generator
+    /// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`:
+    ///
+    /// ```ignore UNSOLVED (ask @compiler-errors, should this error? can we just swap the yields?)
+    /// #![feature(generators)]
+    /// |a| {
+    ///     let x = &vec![3];
+    ///     yield a;
+    ///     yield x[0];
+    /// }
+    /// # ;
+    /// ```
+    GeneratorWitnessMIR(I::DefId, I::SubstsRef),
+
     /// The never type `!`.
     Never,
 
@@ -241,6 +267,7 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
         Placeholder(_) => 23,
         Infer(_) => 24,
         Error(_) => 25,
+        GeneratorWitnessMIR(_, _) => 26,
     }
 }
 
@@ -266,6 +293,7 @@ fn clone(&self) -> Self {
             Closure(d, s) => Closure(d.clone(), s.clone()),
             Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()),
             GeneratorWitness(g) => GeneratorWitness(g.clone()),
+            GeneratorWitnessMIR(d, s) => GeneratorWitnessMIR(d.clone(), s.clone()),
             Never => Never,
             Tuple(t) => Tuple(t.clone()),
             Alias(k, p) => Alias(*k, p.clone()),
@@ -303,6 +331,10 @@ fn eq(&self, other: &TyKind<I>) -> bool {
                     a_d == b_d && a_s == b_s && a_m == b_m
                 }
                 (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g,
+                (
+                    &GeneratorWitnessMIR(ref a_d, ref a_s),
+                    &GeneratorWitnessMIR(ref b_d, ref b_s),
+                ) => a_d == b_d && a_s == b_s,
                 (Tuple(a_t), Tuple(b_t)) => a_t == b_t,
                 (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p,
                 (Param(a_p), Param(b_p)) => a_p == b_p,
@@ -360,6 +392,13 @@ fn cmp(&self, other: &TyKind<I>) -> Ordering {
                     a_d.cmp(b_d).then_with(|| a_s.cmp(b_s).then_with(|| a_m.cmp(b_m)))
                 }
                 (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g.cmp(b_g),
+                (
+                    &GeneratorWitnessMIR(ref a_d, ref a_s),
+                    &GeneratorWitnessMIR(ref b_d, ref b_s),
+                ) => match Ord::cmp(a_d, b_d) {
+                    Ordering::Equal => Ord::cmp(a_s, b_s),
+                    cmp => cmp,
+                },
                 (Tuple(a_t), Tuple(b_t)) => a_t.cmp(b_t),
                 (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i.cmp(b_i).then_with(|| a_p.cmp(b_p)),
                 (Param(a_p), Param(b_p)) => a_p.cmp(b_p),
@@ -421,6 +460,10 @@ fn hash<__H: hash::Hasher>(&self, state: &mut __H) -> () {
                 m.hash(state)
             }
             GeneratorWitness(g) => g.hash(state),
+            GeneratorWitnessMIR(d, s) => {
+                d.hash(state);
+                s.hash(state);
+            }
             Tuple(t) => t.hash(state),
             Alias(i, p) => {
                 i.hash(state);
@@ -461,6 +504,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, s),
             Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, s, m),
             GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", g),
+            GeneratorWitnessMIR(d, s) => f.debug_tuple_field2_finish("GeneratorWitnessMIR", d, s),
             Never => f.write_str("Never"),
             Tuple(t) => f.debug_tuple_field1_finish("Tuple", t),
             Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, a),
@@ -559,6 +603,10 @@ fn encode(&self, e: &mut E) {
             GeneratorWitness(b) => e.emit_enum_variant(disc, |e| {
                 b.encode(e);
             }),
+            GeneratorWitnessMIR(def_id, substs) => e.emit_enum_variant(disc, |e| {
+                def_id.encode(e);
+                substs.encode(e);
+            }),
             Never => e.emit_enum_variant(disc, |_| {}),
             Tuple(substs) => e.emit_enum_variant(disc, |e| {
                 substs.encode(e);
@@ -641,6 +689,7 @@ fn decode(d: &mut D) -> Self {
             23 => Placeholder(Decodable::decode(d)),
             24 => Infer(Decodable::decode(d)),
             25 => Error(Decodable::decode(d)),
+            26 => GeneratorWitnessMIR(Decodable::decode(d), Decodable::decode(d)),
             _ => panic!(
                 "{}",
                 format!(
@@ -742,6 +791,10 @@ fn hash_stable(
             GeneratorWitness(b) => {
                 b.hash_stable(__hcx, __hasher);
             }
+            GeneratorWitnessMIR(def_id, substs) => {
+                def_id.hash_stable(__hcx, __hasher);
+                substs.hash_stable(__hcx, __hasher);
+            }
             Never => {}
             Tuple(substs) => {
                 substs.hash_stable(__hcx, __hasher);
@@ -807,7 +860,7 @@ fn hash_stable(
 ///
 /// Note that inference variables and bound regions are not included
 /// in this diagram. In the case of inference variables, they should
-/// be inferred to some other region from the diagram.  In the case of
+/// be inferred to some other region from the diagram. In the case of
 /// bound regions, they are excluded because they don't make sense to
 /// include -- the diagram indicates the relationship between free
 /// regions.
index 5e1d2f2e314ff904173d04c224797cd2b017b5f2..299bfd779e57a83461efc1167ae9de9e3d603ab8 100644 (file)
@@ -285,11 +285,24 @@ changelog-seen = 2
 # be built if `extended = true`.
 #extended = false
 
-# Installs chosen set of extended tools if `extended = true`. By default builds
-# all extended tools except `rust-demangler`, unless the target is also being
-# built with `profiler = true`. If chosen tool failed to build the installation
-# fails. If `extended = false`, this option is ignored.
-#tools = ["cargo", "rls", "clippy", "rustfmt", "analysis", "src"] # + "rust-demangler" if `profiler`
+# Set of tools to be included in the installation.
+#
+# If `extended = false`, the only one of these built by default is rustdoc.
+#
+# If `extended = true`, they're all included, with the exception of
+# rust-demangler which additionally requires `profiler = true` to be set.
+#
+# If any enabled tool fails to build, the installation fails.
+#tools = [
+#    "cargo",
+#    "clippy",
+#    "rustdoc",
+#    "rustfmt",
+#    "rust-analyzer",
+#    "analysis",
+#    "src",
+#    "rust-demangler",  # if profiler = true
+#]
 
 # Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
 #verbose = 0
index fe6de1cf879b2e2395173f1d4e5d3c80ea2a1fe9..3a797bd5ecaa8ea84e8d90f8a47dab4f5b6c94b9 100644 (file)
@@ -20,7 +20,7 @@
 mod tests;
 
 extern "Rust" {
-    // These are the magic symbols to call the global allocator.  rustc generates
+    // These are the magic symbols to call the global allocator. rustc generates
     // them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
     // (the code expanding that attribute macro generates those functions), or to call
     // the default implementations in std (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
@@ -353,7 +353,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
 
 #[cfg(not(no_global_oom_handling))]
 extern "Rust" {
-    // This is the magic symbol to call the global alloc error handler.  rustc generates
+    // This is the magic symbol to call the global alloc error handler. rustc generates
     // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
     // default implementations below (`__rdl_oom`) otherwise.
     fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
index c1a82e452f6c361d9c1d2cd900fd85bb2e5cb697..ad48315fd70cc070bb116f9f964d4b0b55ad212a 100644 (file)
@@ -48,7 +48,7 @@ unsafe impl<T: ?Sized + Sync> Sync for ThinBox<T> {}
 
 #[unstable(feature = "thin_box", issue = "92791")]
 impl<T> ThinBox<T> {
-    /// Moves a type to the heap with its `Metadata` stored in the heap allocation instead of on
+    /// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on
     /// the stack.
     ///
     /// # Examples
@@ -59,6 +59,8 @@ impl<T> ThinBox<T> {
     ///
     /// let five = ThinBox::new(5);
     /// ```
+    ///
+    /// [`Metadata`]: core::ptr::Pointee::Metadata
     #[cfg(not(no_global_oom_handling))]
     pub fn new(value: T) -> Self {
         let meta = ptr::metadata(&value);
@@ -69,7 +71,7 @@ pub fn new(value: T) -> Self {
 
 #[unstable(feature = "thin_box", issue = "92791")]
 impl<Dyn: ?Sized> ThinBox<Dyn> {
-    /// Moves a type to the heap with its `Metadata` stored in the heap allocation instead of on
+    /// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on
     /// the stack.
     ///
     /// # Examples
@@ -80,6 +82,8 @@ impl<Dyn: ?Sized> ThinBox<Dyn> {
     ///
     /// let thin_slice = ThinBox::<[i32]>::new_unsize([1, 2, 3, 4]);
     /// ```
+    ///
+    /// [`Metadata`]: core::ptr::Pointee::Metadata
     #[cfg(not(no_global_oom_handling))]
     pub fn new_unsize<T>(value: T) -> Self
     where
index 4583bc9a158efc02c059e239c40962faf529f9ce..0b73b1af4eb35abad64b5d6c812293d1a6ad18b1 100644 (file)
 use core::fmt;
 use core::iter::{FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen};
 use core::mem::{self, swap, ManuallyDrop};
+use core::num::NonZeroUsize;
 use core::ops::{Deref, DerefMut};
 use core::ptr;
 
 /// It is a logic error for an item to be modified in such a way that the
 /// item's ordering relative to any other item, as determined by the [`Ord`]
 /// trait, changes while it is in the heap. This is normally only possible
-/// through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. The
+/// through interior mutability, global state, I/O, or unsafe code. The
 /// behavior resulting from such a logic error is not specified, but will
 /// be encapsulated to the `BinaryHeap` that observed the logic error and not
 /// result in undefined behavior. This could include panics, incorrect results,
 /// aborts, memory leaks, and non-termination.
 ///
+/// As long as no elements change their relative order while being in the heap
+/// as described above, the API of `BinaryHeap` guarantees that the heap
+/// invariant remains intact i.e. its methods all behave as documented. For
+/// example if a method is documented as iterating in sorted order, that's
+/// guaranteed to work as long as elements in the heap have not changed order,
+/// even in the presence of closures getting unwinded out of, iterators getting
+/// leaked, and similar foolishness.
+///
 /// # Examples
 ///
 /// ```
@@ -279,7 +288,9 @@ pub struct BinaryHeap<T> {
 #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
 pub struct PeekMut<'a, T: 'a + Ord> {
     heap: &'a mut BinaryHeap<T>,
-    sift: bool,
+    // If a set_len + sift_down are required, this is Some. If a &mut T has not
+    // yet been exposed to peek_mut()'s caller, it's None.
+    original_len: Option<NonZeroUsize>,
 }
 
 #[stable(feature = "collection_debug", since = "1.17.0")]
@@ -292,7 +303,14 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
 impl<T: Ord> Drop for PeekMut<'_, T> {
     fn drop(&mut self) {
-        if self.sift {
+        if let Some(original_len) = self.original_len {
+            // SAFETY: That's how many elements were in the Vec at the time of
+            // the PeekMut::deref_mut call, and therefore also at the time of
+            // the BinaryHeap::peek_mut call. Since the PeekMut did not end up
+            // getting leaked, we are now undoing the leak amplification that
+            // the DerefMut prepared for.
+            unsafe { self.heap.data.set_len(original_len.get()) };
+
             // SAFETY: PeekMut is only instantiated for non-empty heaps.
             unsafe { self.heap.sift_down(0) };
         }
@@ -313,7 +331,26 @@ fn deref(&self) -> &T {
 impl<T: Ord> DerefMut for PeekMut<'_, T> {
     fn deref_mut(&mut self) -> &mut T {
         debug_assert!(!self.heap.is_empty());
-        self.sift = true;
+
+        let len = self.heap.len();
+        if len > 1 {
+            // Here we preemptively leak all the rest of the underlying vector
+            // after the currently max element. If the caller mutates the &mut T
+            // we're about to give them, and then leaks the PeekMut, all these
+            // elements will remain leaked. If they don't leak the PeekMut, then
+            // either Drop or PeekMut::pop will un-leak the vector elements.
+            //
+            // This is technique is described throughout several other places in
+            // the standard library as "leak amplification".
+            unsafe {
+                // SAFETY: len > 1 so len != 0.
+                self.original_len = Some(NonZeroUsize::new_unchecked(len));
+                // SAFETY: len > 1 so all this does for now is leak elements,
+                // which is safe.
+                self.heap.data.set_len(1);
+            }
+        }
+
         // SAFE: PeekMut is only instantiated for non-empty heaps
         unsafe { self.heap.data.get_unchecked_mut(0) }
     }
@@ -323,9 +360,16 @@ impl<'a, T: Ord> PeekMut<'a, T> {
     /// Removes the peeked value from the heap and returns it.
     #[stable(feature = "binary_heap_peek_mut_pop", since = "1.18.0")]
     pub fn pop(mut this: PeekMut<'a, T>) -> T {
-        let value = this.heap.pop().unwrap();
-        this.sift = false;
-        value
+        if let Some(original_len) = this.original_len.take() {
+            // SAFETY: This is how many elements were in the Vec at the time of
+            // the BinaryHeap::peek_mut call.
+            unsafe { this.heap.data.set_len(original_len.get()) };
+
+            // Unlike in Drop, here we don't also need to do a sift_down even if
+            // the caller could've mutated the element. It is removed from the
+            // heap on the next line and pop() is not sensitive to its value.
+        }
+        this.heap.pop().unwrap()
     }
 }
 
@@ -398,8 +442,9 @@ pub fn with_capacity(capacity: usize) -> BinaryHeap<T> {
     /// Returns a mutable reference to the greatest item in the binary heap, or
     /// `None` if it is empty.
     ///
-    /// Note: If the `PeekMut` value is leaked, the heap may be in an
-    /// inconsistent state.
+    /// Note: If the `PeekMut` value is leaked, some heap elements might get
+    /// leaked along with it, but the remaining elements will remain a valid
+    /// heap.
     ///
     /// # Examples
     ///
@@ -426,7 +471,7 @@ pub fn with_capacity(capacity: usize) -> BinaryHeap<T> {
     /// otherwise it's *O*(1).
     #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
     pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
-        if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: false }) }
+        if self.is_empty() { None } else { Some(PeekMut { heap: self, original_len: None }) }
     }
 
     /// Removes the greatest item from the binary heap and returns it, or `None` if it
index 59c516374c0e2790d6c2357b6ed1566afa7c2344..ffbb6c80ac01847999294b6dee8af0b81fa0dc4f 100644 (file)
@@ -1,6 +1,7 @@
 use super::*;
 use crate::boxed::Box;
 use crate::testing::crash_test::{CrashTestDummy, Panic};
+use core::mem;
 use std::iter::TrustedLen;
 use std::panic::{catch_unwind, AssertUnwindSafe};
 
@@ -146,6 +147,24 @@ fn test_peek_mut() {
     assert_eq!(heap.peek(), Some(&9));
 }
 
+#[test]
+fn test_peek_mut_leek() {
+    let data = vec![4, 2, 7];
+    let mut heap = BinaryHeap::from(data);
+    let mut max = heap.peek_mut().unwrap();
+    *max = -1;
+
+    // The PeekMut object's Drop impl would have been responsible for moving the
+    // -1 out of the max position of the BinaryHeap, but we don't run it.
+    mem::forget(max);
+
+    // Absent some mitigation like leak amplification, the -1 would incorrectly
+    // end up in the last position of the returned Vec, with the rest of the
+    // heap's original contents in front of it in sorted order.
+    let sorted_vec = heap.into_sorted_vec();
+    assert!(sorted_vec.is_sorted(), "{:?}", sorted_vec);
+}
+
 #[test]
 fn test_peek_mut_pop() {
     let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
index 4e812529c2cc846d7934672a05202a0eb9db7218..76dabfb429dd503ab945ff002028f0a7f2d375dc 100644 (file)
@@ -87,6 +87,7 @@
 #![warn(missing_debug_implementations)]
 #![warn(missing_docs)]
 #![allow(explicit_outlives_requirements)]
+#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))]
 //
 // Library features:
 #![feature(alloc_layout_extra)]
 #![feature(const_size_of_val)]
 #![feature(const_align_of_val)]
 #![feature(const_ptr_read)]
+#![feature(const_maybe_uninit_zeroed)]
 #![feature(const_maybe_uninit_write)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_refs_to_cell)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(inline_const)]
 #![feature(inplace_iteration)]
+#![cfg_attr(test, feature(is_sorted))]
 #![feature(iter_advance_by)]
 #![feature(iter_next_chunk)]
 #![feature(iter_repeat_n)]
 #![feature(c_unwind)]
 #![feature(with_negative_coherence)]
 #![cfg_attr(test, feature(panic_update_hook))]
+#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))]
 //
 // Rustdoc features:
 #![feature(doc_cfg)]
index c1d853ed652160149e6911c5577e8cc93891f1a9..c9aa23fc4af1f275e98ff6352e4e34480d6044cb 100644 (file)
@@ -2179,7 +2179,7 @@ pub struct Weak<T: ?Sized> {
     // This is a `NonNull` to allow optimizing the size of this type in enums,
     // but it is not necessarily a valid pointer.
     // `Weak::new` sets this to `usize::MAX` so that it doesn’t need
-    // to allocate space on the heap.  That's not a value a real pointer
+    // to allocate space on the heap. That's not a value a real pointer
     // will ever have because RcBox has alignment at least 2.
     // This is only possible when `T: Sized`; unsized `T` never dangle.
     ptr: NonNull<RcBox<T>>,
index e9886fc5717990ec4a93feafa5901aa4235ca9fd..fecacc2bb639508836b4090fa22280a368051a67 100644 (file)
 use core::mem::{self, SizedTypeProperties};
 #[cfg(not(no_global_oom_handling))]
 use core::ptr;
+#[cfg(not(no_global_oom_handling))]
+use core::slice::sort;
 
 use crate::alloc::Allocator;
 #[cfg(not(no_global_oom_handling))]
-use crate::alloc::Global;
+use crate::alloc::{self, Global};
 #[cfg(not(no_global_oom_handling))]
 use crate::borrow::ToOwned;
 use crate::boxed::Box;
@@ -206,7 +208,7 @@ pub fn sort(&mut self)
     where
         T: Ord,
     {
-        merge_sort(self, T::lt);
+        stable_sort(self, T::lt);
     }
 
     /// Sorts the slice with a comparator function.
@@ -262,7 +264,7 @@ pub fn sort_by<F>(&mut self, mut compare: F)
     where
         F: FnMut(&T, &T) -> Ordering,
     {
-        merge_sort(self, |a, b| compare(a, b) == Less);
+        stable_sort(self, |a, b| compare(a, b) == Less);
     }
 
     /// Sorts the slice with a key extraction function.
@@ -305,7 +307,7 @@ pub fn sort_by_key<K, F>(&mut self, mut f: F)
         F: FnMut(&T) -> K,
         K: Ord,
     {
-        merge_sort(self, |a, b| f(a).lt(&f(b)));
+        stable_sort(self, |a, b| f(a).lt(&f(b)));
     }
 
     /// Sorts the slice with a key extraction function.
@@ -812,324 +814,52 @@ fn clone_into(&self, target: &mut Vec<T>) {
 // Sorting
 ////////////////////////////////////////////////////////////////////////////////
 
-/// Inserts `v[0]` into pre-sorted sequence `v[1..]` so that whole `v[..]` becomes sorted.
-///
-/// This is the integral subroutine of insertion sort.
-#[cfg(not(no_global_oom_handling))]
-fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
-where
-    F: FnMut(&T, &T) -> bool,
-{
-    if v.len() >= 2 && is_less(&v[1], &v[0]) {
-        unsafe {
-            // There are three ways to implement insertion here:
-            //
-            // 1. Swap adjacent elements until the first one gets to its final destination.
-            //    However, this way we copy data around more than is necessary. If elements are big
-            //    structures (costly to copy), this method will be slow.
-            //
-            // 2. Iterate until the right place for the first element is found. Then shift the
-            //    elements succeeding it to make room for it and finally place it into the
-            //    remaining hole. This is a good method.
-            //
-            // 3. Copy the first element into a temporary variable. Iterate until the right place
-            //    for it is found. As we go along, copy every traversed element into the slot
-            //    preceding it. Finally, copy data from the temporary variable into the remaining
-            //    hole. This method is very good. Benchmarks demonstrated slightly better
-            //    performance than with the 2nd method.
-            //
-            // All methods were benchmarked, and the 3rd showed best results. So we chose that one.
-            let tmp = mem::ManuallyDrop::new(ptr::read(&v[0]));
-
-            // Intermediate state of the insertion process is always tracked by `hole`, which
-            // serves two purposes:
-            // 1. Protects integrity of `v` from panics in `is_less`.
-            // 2. Fills the remaining hole in `v` in the end.
-            //
-            // Panic safety:
-            //
-            // If `is_less` panics at any point during the process, `hole` will get dropped and
-            // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it
-            // initially held exactly once.
-            let mut hole = InsertionHole { src: &*tmp, dest: &mut v[1] };
-            ptr::copy_nonoverlapping(&v[1], &mut v[0], 1);
-
-            for i in 2..v.len() {
-                if !is_less(&v[i], &*tmp) {
-                    break;
-                }
-                ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1);
-                hole.dest = &mut v[i];
-            }
-            // `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`.
-        }
-    }
-
-    // When dropped, copies from `src` into `dest`.
-    struct InsertionHole<T> {
-        src: *const T,
-        dest: *mut T,
-    }
-
-    impl<T> Drop for InsertionHole<T> {
-        fn drop(&mut self) {
-            unsafe {
-                ptr::copy_nonoverlapping(self.src, self.dest, 1);
-            }
-        }
-    }
-}
-
-/// Merges non-decreasing runs `v[..mid]` and `v[mid..]` using `buf` as temporary storage, and
-/// stores the result into `v[..]`.
-///
-/// # Safety
-///
-/// The two slices must be non-empty and `mid` must be in bounds. Buffer `buf` must be long enough
-/// to hold a copy of the shorter slice. Also, `T` must not be a zero-sized type.
-#[cfg(not(no_global_oom_handling))]
-unsafe fn merge<T, F>(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F)
-where
-    F: FnMut(&T, &T) -> bool,
-{
-    let len = v.len();
-    let v = v.as_mut_ptr();
-    let (v_mid, v_end) = unsafe { (v.add(mid), v.add(len)) };
-
-    // The merge process first copies the shorter run into `buf`. Then it traces the newly copied
-    // run and the longer run forwards (or backwards), comparing their next unconsumed elements and
-    // copying the lesser (or greater) one into `v`.
-    //
-    // As soon as the shorter run is fully consumed, the process is done. If the longer run gets
-    // consumed first, then we must copy whatever is left of the shorter run into the remaining
-    // hole in `v`.
-    //
-    // Intermediate state of the process is always tracked by `hole`, which serves two purposes:
-    // 1. Protects integrity of `v` from panics in `is_less`.
-    // 2. Fills the remaining hole in `v` if the longer run gets consumed first.
-    //
-    // Panic safety:
-    //
-    // If `is_less` panics at any point during the process, `hole` will get dropped and fill the
-    // hole in `v` with the unconsumed range in `buf`, thus ensuring that `v` still holds every
-    // object it initially held exactly once.
-    let mut hole;
-
-    if mid <= len - mid {
-        // The left run is shorter.
-        unsafe {
-            ptr::copy_nonoverlapping(v, buf, mid);
-            hole = MergeHole { start: buf, end: buf.add(mid), dest: v };
-        }
-
-        // Initially, these pointers point to the beginnings of their arrays.
-        let left = &mut hole.start;
-        let mut right = v_mid;
-        let out = &mut hole.dest;
-
-        while *left < hole.end && right < v_end {
-            // Consume the lesser side.
-            // If equal, prefer the left run to maintain stability.
-            unsafe {
-                let to_copy = if is_less(&*right, &**left) {
-                    get_and_increment(&mut right)
-                } else {
-                    get_and_increment(left)
-                };
-                ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1);
-            }
-        }
-    } else {
-        // The right run is shorter.
-        unsafe {
-            ptr::copy_nonoverlapping(v_mid, buf, len - mid);
-            hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid };
-        }
-
-        // Initially, these pointers point past the ends of their arrays.
-        let left = &mut hole.dest;
-        let right = &mut hole.end;
-        let mut out = v_end;
-
-        while v < *left && buf < *right {
-            // Consume the greater side.
-            // If equal, prefer the right run to maintain stability.
-            unsafe {
-                let to_copy = if is_less(&*right.sub(1), &*left.sub(1)) {
-                    decrement_and_get(left)
-                } else {
-                    decrement_and_get(right)
-                };
-                ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1);
-            }
-        }
-    }
-    // Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of
-    // it will now be copied into the hole in `v`.
-
-    unsafe fn get_and_increment<T>(ptr: &mut *mut T) -> *mut T {
-        let old = *ptr;
-        *ptr = unsafe { ptr.add(1) };
-        old
-    }
-
-    unsafe fn decrement_and_get<T>(ptr: &mut *mut T) -> *mut T {
-        *ptr = unsafe { ptr.sub(1) };
-        *ptr
-    }
-
-    // When dropped, copies the range `start..end` into `dest..`.
-    struct MergeHole<T> {
-        start: *mut T,
-        end: *mut T,
-        dest: *mut T,
-    }
-
-    impl<T> Drop for MergeHole<T> {
-        fn drop(&mut self) {
-            // `T` is not a zero-sized type, and these are pointers into a slice's elements.
-            unsafe {
-                let len = self.end.sub_ptr(self.start);
-                ptr::copy_nonoverlapping(self.start, self.dest, len);
-            }
-        }
-    }
-}
-
-/// This merge sort borrows some (but not all) ideas from TimSort, which is described in detail
-/// [here](https://github.com/python/cpython/blob/main/Objects/listsort.txt).
-///
-/// The algorithm identifies strictly descending and non-descending subsequences, which are called
-/// natural runs. There is a stack of pending runs yet to be merged. Each newly found run is pushed
-/// onto the stack, and then some pairs of adjacent runs are merged until these two invariants are
-/// satisfied:
-///
-/// 1. for every `i` in `1..runs.len()`: `runs[i - 1].len > runs[i].len`
-/// 2. for every `i` in `2..runs.len()`: `runs[i - 2].len > runs[i - 1].len + runs[i].len`
-///
-/// The invariants ensure that the total running time is *O*(*n* \* log(*n*)) worst-case.
+#[inline]
 #[cfg(not(no_global_oom_handling))]
-fn merge_sort<T, F>(v: &mut [T], mut is_less: F)
+fn stable_sort<T, F>(v: &mut [T], mut is_less: F)
 where
     F: FnMut(&T, &T) -> bool,
 {
-    // Slices of up to this length get sorted using insertion sort.
-    const MAX_INSERTION: usize = 20;
-    // Very short runs are extended using insertion sort to span at least this many elements.
-    const MIN_RUN: usize = 10;
-
-    // Sorting has no meaningful behavior on zero-sized types.
     if T::IS_ZST {
+        // Sorting has no meaningful behavior on zero-sized types. Do nothing.
         return;
     }
 
-    let len = v.len();
-
-    // Short arrays get sorted in-place via insertion sort to avoid allocations.
-    if len <= MAX_INSERTION {
-        if len >= 2 {
-            for i in (0..len - 1).rev() {
-                insert_head(&mut v[i..], &mut is_less);
-            }
-        }
-        return;
-    }
-
-    // Allocate a buffer to use as scratch memory. We keep the length 0 so we can keep in it
-    // shallow copies of the contents of `v` without risking the dtors running on copies if
-    // `is_less` panics. When merging two sorted runs, this buffer holds a copy of the shorter run,
-    // which will always have length at most `len / 2`.
-    let mut buf = Vec::with_capacity(len / 2);
+    let elem_alloc_fn = |len: usize| -> *mut T {
+        // SAFETY: Creating the layout is safe as long as merge_sort never calls this with len >
+        // v.len(). Alloc in general will only be used as 'shadow-region' to store temporary swap
+        // elements.
+        unsafe { alloc::alloc(alloc::Layout::array::<T>(len).unwrap_unchecked()) as *mut T }
+    };
 
-    // In order to identify natural runs in `v`, we traverse it backwards. That might seem like a
-    // strange decision, but consider the fact that merges more often go in the opposite direction
-    // (forwards). According to benchmarks, merging forwards is slightly faster than merging
-    // backwards. To conclude, identifying runs by traversing backwards improves performance.
-    let mut runs = vec![];
-    let mut end = len;
-    while end > 0 {
-        // Find the next natural run, and reverse it if it's strictly descending.
-        let mut start = end - 1;
-        if start > 0 {
-            start -= 1;
-            unsafe {
-                if is_less(v.get_unchecked(start + 1), v.get_unchecked(start)) {
-                    while start > 0 && is_less(v.get_unchecked(start), v.get_unchecked(start - 1)) {
-                        start -= 1;
-                    }
-                    v[start..end].reverse();
-                } else {
-                    while start > 0 && !is_less(v.get_unchecked(start), v.get_unchecked(start - 1))
-                    {
-                        start -= 1;
-                    }
-                }
-            }
-        }
-
-        // Insert some more elements into the run if it's too short. Insertion sort is faster than
-        // merge sort on short sequences, so this significantly improves performance.
-        while start > 0 && end - start < MIN_RUN {
-            start -= 1;
-            insert_head(&mut v[start..end], &mut is_less);
+    let elem_dealloc_fn = |buf_ptr: *mut T, len: usize| {
+        // SAFETY: Creating the layout is safe as long as merge_sort never calls this with len >
+        // v.len(). The caller must ensure that buf_ptr was created by elem_alloc_fn with the same
+        // len.
+        unsafe {
+            alloc::dealloc(buf_ptr as *mut u8, alloc::Layout::array::<T>(len).unwrap_unchecked());
         }
+    };
 
-        // Push this run onto the stack.
-        runs.push(Run { start, len: end - start });
-        end = start;
-
-        // Merge some pairs of adjacent runs to satisfy the invariants.
-        while let Some(r) = collapse(&runs) {
-            let left = runs[r + 1];
-            let right = runs[r];
-            unsafe {
-                merge(
-                    &mut v[left.start..right.start + right.len],
-                    left.len,
-                    buf.as_mut_ptr(),
-                    &mut is_less,
-                );
-            }
-            runs[r] = Run { start: left.start, len: left.len + right.len };
-            runs.remove(r + 1);
+    let run_alloc_fn = |len: usize| -> *mut sort::TimSortRun {
+        // SAFETY: Creating the layout is safe as long as merge_sort never calls this with an
+        // obscene length or 0.
+        unsafe {
+            alloc::alloc(alloc::Layout::array::<sort::TimSortRun>(len).unwrap_unchecked())
+                as *mut sort::TimSortRun
         }
-    }
-
-    // Finally, exactly one run must remain in the stack.
-    debug_assert!(runs.len() == 1 && runs[0].start == 0 && runs[0].len == len);
+    };
 
-    // Examines the stack of runs and identifies the next pair of runs to merge. More specifically,
-    // if `Some(r)` is returned, that means `runs[r]` and `runs[r + 1]` must be merged next. If the
-    // algorithm should continue building a new run instead, `None` is returned.
-    //
-    // TimSort is infamous for its buggy implementations, as described here:
-    // http://envisage-project.eu/timsort-specification-and-verification/
-    //
-    // The gist of the story is: we must enforce the invariants on the top four runs on the stack.
-    // Enforcing them on just top three is not sufficient to ensure that the invariants will still
-    // hold for *all* runs in the stack.
-    //
-    // This function correctly checks invariants for the top four runs. Additionally, if the top
-    // run starts at index 0, it will always demand a merge operation until the stack is fully
-    // collapsed, in order to complete the sort.
-    #[inline]
-    fn collapse(runs: &[Run]) -> Option<usize> {
-        let n = runs.len();
-        if n >= 2
-            && (runs[n - 1].start == 0
-                || runs[n - 2].len <= runs[n - 1].len
-                || (n >= 3 && runs[n - 3].len <= runs[n - 2].len + runs[n - 1].len)
-                || (n >= 4 && runs[n - 4].len <= runs[n - 3].len + runs[n - 2].len))
-        {
-            if n >= 3 && runs[n - 3].len < runs[n - 1].len { Some(n - 3) } else { Some(n - 2) }
-        } else {
-            None
+    let run_dealloc_fn = |buf_ptr: *mut sort::TimSortRun, len: usize| {
+        // SAFETY: The caller must ensure that buf_ptr was created by elem_alloc_fn with the same
+        // len.
+        unsafe {
+            alloc::dealloc(
+                buf_ptr as *mut u8,
+                alloc::Layout::array::<sort::TimSortRun>(len).unwrap_unchecked(),
+            );
         }
-    }
+    };
 
-    #[derive(Clone, Copy)]
-    struct Run {
-        start: usize,
-        len: usize,
-    }
+    sort::merge_sort(v, &mut is_less, elem_alloc_fn, elem_dealloc_fn, run_alloc_fn, run_dealloc_fn);
 }
index b28d20cda179ec32054515d56dad13d303e387ee..afbe5cfaf8ef9dbe0cbe87436cc50e249c1d7ffa 100644 (file)
@@ -559,10 +559,9 @@ pub fn repeat(&self, n: usize) -> String {
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
     pub fn to_ascii_uppercase(&self) -> String {
-        let mut bytes = self.as_bytes().to_vec();
-        bytes.make_ascii_uppercase();
-        // make_ascii_uppercase() preserves the UTF-8 invariant.
-        unsafe { String::from_utf8_unchecked(bytes) }
+        let mut s = self.to_owned();
+        s.make_ascii_uppercase();
+        s
     }
 
     /// Returns a copy of this string where each character is mapped to its
@@ -592,10 +591,9 @@ pub fn to_ascii_uppercase(&self) -> String {
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
     pub fn to_ascii_lowercase(&self) -> String {
-        let mut bytes = self.as_bytes().to_vec();
-        bytes.make_ascii_lowercase();
-        // make_ascii_lowercase() preserves the UTF-8 invariant.
-        unsafe { String::from_utf8_unchecked(bytes) }
+        let mut s = self.to_owned();
+        s.make_ascii_lowercase();
+        s
     }
 }
 
index d833d4d1dfbd327a5f53b606498e5e717cbcae69..9bc9182f7b53c3b170d0634ed959164f5b4204ea 100644 (file)
@@ -295,7 +295,7 @@ pub struct Weak<T: ?Sized> {
     // This is a `NonNull` to allow optimizing the size of this type in enums,
     // but it is not necessarily a valid pointer.
     // `Weak::new` sets this to `usize::MAX` so that it doesn’t need
-    // to allocate space on the heap.  That's not a value a real pointer
+    // to allocate space on the heap. That's not a value a real pointer
     // will ever have because RcBox has alignment at least 2.
     // This is only possible when `T: Sized`; unsized `T` never dangle.
     ptr: NonNull<ArcInner<T>>,
@@ -654,6 +654,20 @@ pub fn try_new_zeroed() -> Result<Arc<mem::MaybeUninit<T>>, AllocError> {
     ///
     /// This will succeed even if there are outstanding weak references.
     ///
+    // FIXME: when `Arc::into_inner` is stabilized, add this paragraph:
+    /*
+    /// It is strongly recommended to use [`Arc::into_inner`] instead if you don't
+    /// want to keep the `Arc` in the [`Err`] case.
+    /// Immediately dropping the [`Err`] payload, like in the expression
+    /// `Arc::try_unwrap(this).ok()`, can still cause the strong count to
+    /// drop to zero and the inner value of the `Arc` to be dropped:
+    /// For instance if two threads execute this expression in parallel, then
+    /// there is a race condition. The threads could first both check whether they
+    /// have the last clone of their `Arc` via `Arc::try_unwrap`, and then
+    /// both drop their `Arc` in the call to [`ok`][`Result::ok`],
+    /// taking the strong count from two down to zero.
+    ///
+     */
     /// # Examples
     ///
     /// ```
@@ -685,6 +699,137 @@ pub fn try_unwrap(this: Self) -> Result<T, Self> {
             Ok(elem)
         }
     }
+
+    /// Returns the inner value, if the `Arc` has exactly one strong reference.
+    ///
+    /// Otherwise, [`None`] is returned and the `Arc` is dropped.
+    ///
+    /// This will succeed even if there are outstanding weak references.
+    ///
+    /// If `Arc::into_inner` is called on every clone of this `Arc`,
+    /// it is guaranteed that exactly one of the calls returns the inner value.
+    /// This means in particular that the inner value is not dropped.
+    ///
+    /// The similar expression `Arc::try_unwrap(this).ok()` does not
+    /// offer such a guarantee. See the last example below.
+    //
+    // FIXME: when `Arc::into_inner` is stabilized, add this to end
+    // of the previous sentence:
+    /*
+    /// and the documentation of [`Arc::try_unwrap`].
+     */
+    ///
+    /// # Examples
+    ///
+    /// Minimal example demonstrating the guarantee that `Arc::into_inner` gives.
+    /// ```
+    /// #![feature(arc_into_inner)]
+    ///
+    /// use std::sync::Arc;
+    ///
+    /// let x = Arc::new(3);
+    /// let y = Arc::clone(&x);
+    ///
+    /// // Two threads calling `Arc::into_inner` on both clones of an `Arc`:
+    /// let x_thread = std::thread::spawn(|| Arc::into_inner(x));
+    /// let y_thread = std::thread::spawn(|| Arc::into_inner(y));
+    ///
+    /// let x_inner_value = x_thread.join().unwrap();
+    /// let y_inner_value = y_thread.join().unwrap();
+    ///
+    /// // One of the threads is guaranteed to receive the inner value:
+    /// assert!(matches!(
+    ///     (x_inner_value, y_inner_value),
+    ///     (None, Some(3)) | (Some(3), None)
+    /// ));
+    /// // The result could also be `(None, None)` if the threads called
+    /// // `Arc::try_unwrap(x).ok()` and `Arc::try_unwrap(y).ok()` instead.
+    /// ```
+    ///
+    /// A more practical example demonstrating the need for `Arc::into_inner`:
+    /// ```
+    /// #![feature(arc_into_inner)]
+    ///
+    /// use std::sync::Arc;
+    ///
+    /// // Definition of a simple singly linked list using `Arc`:
+    /// #[derive(Clone)]
+    /// struct LinkedList<T>(Option<Arc<Node<T>>>);
+    /// struct Node<T>(T, Option<Arc<Node<T>>>);
+    ///
+    /// // Dropping a long `LinkedList<T>` relying on the destructor of `Arc`
+    /// // can cause a stack overflow. To prevent this, we can provide a
+    /// // manual `Drop` implementation that does the destruction in a loop:
+    /// impl<T> Drop for LinkedList<T> {
+    ///     fn drop(&mut self) {
+    ///         let mut link = self.0.take();
+    ///         while let Some(arc_node) = link.take() {
+    ///             if let Some(Node(_value, next)) = Arc::into_inner(arc_node) {
+    ///                 link = next;
+    ///             }
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// // Implementation of `new` and `push` omitted
+    /// impl<T> LinkedList<T> {
+    ///     /* ... */
+    /// #   fn new() -> Self {
+    /// #       LinkedList(None)
+    /// #   }
+    /// #   fn push(&mut self, x: T) {
+    /// #       self.0 = Some(Arc::new(Node(x, self.0.take())));
+    /// #   }
+    /// }
+    ///
+    /// // The following code could have still caused a stack overflow
+    /// // despite the manual `Drop` impl if that `Drop` impl had used
+    /// // `Arc::try_unwrap(arc).ok()` instead of `Arc::into_inner(arc)`.
+    ///
+    /// // Create a long list and clone it
+    /// let mut x = LinkedList::new();
+    /// for i in 0..100000 {
+    ///     x.push(i); // Adds i to the front of x
+    /// }
+    /// let y = x.clone();
+    ///
+    /// // Drop the clones in parallel
+    /// let x_thread = std::thread::spawn(|| drop(x));
+    /// let y_thread = std::thread::spawn(|| drop(y));
+    /// x_thread.join().unwrap();
+    /// y_thread.join().unwrap();
+    /// ```
+
+    // FIXME: when `Arc::into_inner` is stabilized, adjust above documentation
+    // and the documentation of `Arc::try_unwrap` according to the `FIXME`s. Also
+    // open an issue on rust-lang/rust-clippy, asking for a lint against
+    // `Arc::try_unwrap(...).ok()`.
+    #[inline]
+    #[unstable(feature = "arc_into_inner", issue = "106894")]
+    pub fn into_inner(this: Self) -> Option<T> {
+        // Make sure that the ordinary `Drop` implementation isn’t called as well
+        let mut this = mem::ManuallyDrop::new(this);
+
+        // Following the implementation of `drop` and `drop_slow`
+        if this.inner().strong.fetch_sub(1, Release) != 1 {
+            return None;
+        }
+
+        acquire!(this.inner().strong);
+
+        // SAFETY: This mirrors the line
+        //
+        //     unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) };
+        //
+        // in `drop_slow`. Instead of dropping the value behind the pointer,
+        // it is read and eventually returned; `ptr::read` has the same
+        // safety conditions as `ptr::drop_in_place`.
+        let inner = unsafe { ptr::read(Self::get_mut_unchecked(&mut this)) };
+
+        drop(Weak { ptr: this.ptr });
+
+        Some(inner)
+    }
 }
 
 impl<T> Arc<[T]> {
@@ -1656,7 +1801,7 @@ fn is_unique(&mut self) -> bool {
         //
         // The acquire label here ensures a happens-before relationship with any
         // writes to `strong` (in particular in `Weak::upgrade`) prior to decrements
-        // of the `weak` count (via `Weak::drop`, which uses release).  If the upgraded
+        // of the `weak` count (via `Weak::drop`, which uses release). If the upgraded
         // weak ref was never dropped, the CAS here will fail so we do not care to synchronize.
         if self.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() {
             // This needs to be an `Acquire` to synchronize with the decrement of the `strong`
@@ -1712,7 +1857,7 @@ fn drop(&mut self) {
         }
 
         // This fence is needed to prevent reordering of use of the data and
-        // deletion of the data.  Because it is marked `Release`, the decreasing
+        // deletion of the data. Because it is marked `Release`, the decreasing
         // of the reference count synchronizes with this `Acquire` fence. This
         // means that use of the data happens before decreasing the reference
         // count, which happens before this fence, which happens before the
@@ -2172,7 +2317,7 @@ fn clone(&self) -> Weak<T> {
         } else {
             return Weak { ptr: self.ptr };
         };
-        // See comments in Arc::clone() for why this is relaxed.  This can use a
+        // See comments in Arc::clone() for why this is relaxed. This can use a
         // fetch_add (ignoring the lock) because the weak count is only locked
         // where are *no other* weak pointers in existence. (So we can't be
         // running this code in that case).
index 0fae8953aa2c771532d10f90c79b795eb2ef1450..863d58bdf4d9cdad35f341f1aeb519a67f9bb63f 100644 (file)
@@ -101,6 +101,38 @@ fn try_unwrap() {
     assert_eq!(Arc::try_unwrap(x), Ok(5));
 }
 
+#[test]
+fn into_inner() {
+    for _ in 0..100
+    // ^ Increase chances of hitting potential race conditions
+    {
+        let x = Arc::new(3);
+        let y = Arc::clone(&x);
+        let r_thread = std::thread::spawn(|| Arc::into_inner(x));
+        let s_thread = std::thread::spawn(|| Arc::into_inner(y));
+        let r = r_thread.join().expect("r_thread panicked");
+        let s = s_thread.join().expect("s_thread panicked");
+        assert!(
+            matches!((r, s), (None, Some(3)) | (Some(3), None)),
+            "assertion failed: unexpected result `{:?}`\
+            \n  expected `(None, Some(3))` or `(Some(3), None)`",
+            (r, s),
+        );
+    }
+
+    let x = Arc::new(3);
+    assert_eq!(Arc::into_inner(x), Some(3));
+
+    let x = Arc::new(4);
+    let y = Arc::clone(&x);
+    assert_eq!(Arc::into_inner(x), None);
+    assert_eq!(Arc::into_inner(y), Some(4));
+
+    let x = Arc::new(5);
+    let _w = Arc::downgrade(&x);
+    assert_eq!(Arc::into_inner(x), Some(5));
+}
+
 #[test]
 fn into_from_raw() {
     let x = Arc::new(Box::new("hello"));
index 541f99bcfaba4582ad801dc81de5075c5830aed3..2b1a787cc549929231be0dfe33f1b8b57d1e9441 100644 (file)
@@ -223,9 +223,9 @@ fn drop(&mut self) {
         }
 
         // as_slice() must only be called when iter.len() is > 0 because
-        // vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate
-        // the iterator's internal pointers. Creating a reference to deallocated memory
-        // is invalid even when it is zero-length
+        // it also gets touched by vec::Splice which may turn it into a dangling pointer
+        // which would make it and the vec pointer point to different allocations which would
+        // lead to invalid pointer arithmetic below.
         let drop_ptr = iter.as_slice().as_ptr();
 
         unsafe {
index b207b3210f1aa22ae6edcf989ab68b7f5b14bff1..37966007eb7e43eb1fb661d8925567b303f905ba 100644 (file)
@@ -40,7 +40,7 @@ pub struct IntoIter<
     // to avoid dropping the allocator twice we need to wrap it into ManuallyDrop
     pub(super) alloc: ManuallyDrop<A>,
     pub(super) ptr: *const T,
-    pub(super) end: *const T, // If T is a ZST, this is actually ptr+len.  This encoding is picked so that
+    pub(super) end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
                               // ptr == end is a quick test for the Iterator being empty, that works
                               // for both ZST and non-ZST.
 }
@@ -146,9 +146,9 @@ pub(crate) fn into_vecdeque(self) -> VecDeque<T, A> {
         let mut this = ManuallyDrop::new(self);
 
         // SAFETY: This allocation originally came from a `Vec`, so it passes
-        // all those checks.  We have `this.buf` ≤ `this.ptr` ≤ `this.end`,
+        // all those checks. We have `this.buf` ≤ `this.ptr` ≤ `this.end`,
         // so the `sub_ptr`s below cannot wrap, and will produce a well-formed
-        // range.  `end` ≤ `buf + cap`, so the range will be in-bounds.
+        // range. `end` ≤ `buf + cap`, so the range will be in-bounds.
         // Taking `alloc` is ok because nothing else is going to look at it,
         // since our `Drop` impl isn't going to run so there's no more code.
         unsafe {
index 8e652d676dc010a740a44f60a92934b99bd0c11e..cb9adf05c25b0efe8351608e7293452975bd08b9 100644 (file)
@@ -4,7 +4,8 @@
 
 #[rustc_specialization_trait]
 pub(super) unsafe trait IsZero {
-    /// Whether this value's representation is all zeros
+    /// Whether this value's representation is all zeros,
+    /// or can be represented with all zeroes.
     fn is_zero(&self) -> bool;
 }
 
@@ -57,7 +58,7 @@ fn is_zero(&self) -> bool {
     #[inline]
     fn is_zero(&self) -> bool {
         // Because this is generated as a runtime check, it's not obvious that
-        // it's worth doing if the array is really long.  The threshold here
+        // it's worth doing if the array is really long. The threshold here
         // is largely arbitrary, but was picked because as of 2022-07-01 LLVM
         // fails to const-fold the check in `vec![[1; 32]; n]`
         // See https://github.com/rust-lang/rust/pull/97581#issuecomment-1166628022
@@ -147,6 +148,23 @@ fn is_zero(&self) -> bool {
     NonZeroIsize,
 );
 
+macro_rules! impl_is_zero_option_of_num {
+    ($($t:ty,)+) => {$(
+        unsafe impl IsZero for Option<$t> {
+            #[inline]
+            fn is_zero(&self) -> bool {
+                const {
+                    let none: Self = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
+                    assert!(none.is_none());
+                }
+                self.is_none()
+            }
+        }
+    )+};
+}
+
+impl_is_zero_option_of_num!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize,);
+
 unsafe impl<T: IsZero> IsZero for Wrapping<T> {
     #[inline]
     fn is_zero(&self) -> bool {
index 36cfac8ee9e17da0dde403e785c0a09efd324898..36b0b3c9e7cc072aca6f39d2f165d277d52cbdc3 100644 (file)
@@ -2429,7 +2429,7 @@ pub fn extend_from_within<R>(&mut self, src: R)
         self.reserve(range.len());
 
         // SAFETY:
-        // - `slice::range` guarantees  that the given range is valid for indexing self
+        // - `slice::range` guarantees that the given range is valid for indexing self
         unsafe {
             self.spec_extend_from_within(range);
         }
@@ -2686,7 +2686,7 @@ fn clone(&self) -> Self {
 
     // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
     // required for this method definition, is not available. Instead use the
-    // `slice::to_vec`  function which is only available with cfg(test)
+    // `slice::to_vec` function which is only available with cfg(test)
     // NB see the slice::hack module in slice.rs for more information
     #[cfg(test)]
     fn clone(&self) -> Self {
index bad765c7f51fab944b3de89a3a956de2dd42f158..1861147fe72fb676920d5a8ac8847288253e6797 100644 (file)
@@ -54,6 +54,12 @@ impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
 impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
     fn drop(&mut self) {
         self.drain.by_ref().for_each(drop);
+        // At this point draining is done and the only remaining tasks are splicing
+        // and moving things into the final place.
+        // Which means we can replace the slice::Iter with pointers that won't point to deallocated
+        // memory, so that Drain::drop is still allowed to call iter.len(), otherwise it would break
+        // the ptr.sub_ptr contract.
+        self.drain.iter = (&[]).iter();
 
         unsafe {
             if self.drain.tail_len == 0 {
index d6d2b055b2395e8563543ed0628189b5b975823c..2a93a242d51744e02e5fa196579898a67f9d682d 100644 (file)
@@ -1,7 +1,6 @@
 #![feature(allocator_api)]
 #![feature(alloc_layout_extra)]
 #![feature(assert_matches)]
-#![feature(box_syntax)]
 #![feature(btree_drain_filter)]
 #![feature(cow_is_borrowed)]
 #![feature(const_box)]
index 87adcead8f62d69ba7dbcdcb4c5f331aa276b414..2f07c2911a50264aee57ab1a67b966a869045ef3 100644 (file)
@@ -1849,7 +1849,7 @@ fn next_then_drop<I: Iterator>(mut i: I) {
     }
 
     // Test that, if we reserved enough space, adding and removing elements does not
-    // invalidate references into the vector (such as `v0`).  This test also
+    // invalidate references into the vector (such as `v0`). This test also
     // runs in Miri, which would detect such problems.
     // Note that this test does *not* constitute a stable guarantee that all these functions do not
     // reallocate! Only what is explicitly documented at
index 9ca4947ed8f8bb7978870a8a6c01880f7b1d8bdc..c0fb0d993c3ed939ad5087a1dbb04f555463115e 100644 (file)
@@ -662,7 +662,8 @@ pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
 /// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth
 /// noting that the hashes and ordering will vary between Rust releases. Beware
 /// of relying on them inside of your code!
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+#[derive(Clone, Copy, Debug, Hash, Eq)]
+#[derive_const(PartialEq, PartialOrd, Ord)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct TypeId {
     t: u64,
index b91c630183d4fe707231b70e483f4b202d5dafde..8259c087d22e4ff13cce9566ed8a828a169f0977 100644 (file)
@@ -109,8 +109,8 @@ impl<T, const N: usize> IntoIter<T, N> {
     /// use std::array::IntoIter;
     /// use std::mem::MaybeUninit;
     ///
-    /// # // Hi!  Thanks for reading the code.  This is restricted to `Copy` because
-    /// # // otherwise it could leak.  A fully-general version this would need a drop
+    /// # // Hi!  Thanks for reading the code. This is restricted to `Copy` because
+    /// # // otherwise it could leak. A fully-general version this would need a drop
     /// # // guard to handle panics from the iterator, but this works for an example.
     /// fn next_chunk<T: Copy, const N: usize>(
     ///     it: &mut impl Iterator<Item = T>,
@@ -211,7 +211,7 @@ pub const fn empty() -> Self {
         let initialized = 0..0;
 
         // SAFETY: We're telling it that none of the elements are initialized,
-        // which is trivially true.  And ∀N: usize, 0 <= N.
+        // which is trivially true. And ∀N: usize, 0 <= N.
         unsafe { Self::new_unchecked(buffer, initialized) }
     }
 
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 7152300abcbf3a446cca031d797040d23abb2353..d2fac23ff18be7542729e0b6793d796daad17dd5 100644 (file)
@@ -28,6 +28,7 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
 #[rustc_has_incoherent_inherent_impls]
+#[cfg_attr(not(bootstrap), allow(multiple_supertrait_upcastable))]
 pub trait Error: Debug + Display {
     /// The lower-level source of this error, if any.
     ///
index fa5073e3304d72e93dff7a042804e043b234caa8..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")]
@@ -1355,11 +1374,11 @@ fn wrap_buf<'b, 'c, F>(&'b mut self, wrap: F) -> Formatter<'c>
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{}", Foo::new(2)), "2");
-    /// assert_eq!(&format!("{}", Foo::new(-1)), "-1");
-    /// assert_eq!(&format!("{}", Foo::new(0)), "0");
-    /// assert_eq!(&format!("{:#}", Foo::new(-1)), "-Foo 1");
-    /// assert_eq!(&format!("{:0>#8}", Foo::new(-1)), "00-Foo 1");
+    /// assert_eq!(format!("{}", Foo::new(2)), "2");
+    /// assert_eq!(format!("{}", Foo::new(-1)), "-1");
+    /// assert_eq!(format!("{}", Foo::new(0)), "0");
+    /// assert_eq!(format!("{:#}", Foo::new(-1)), "-Foo 1");
+    /// assert_eq!(format!("{:0>#8}", Foo::new(-1)), "00-Foo 1");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn pad_integral(&mut self, is_nonnegative: bool, prefix: &str, buf: &str) -> Result {
@@ -1452,8 +1471,8 @@ fn write_prefix(f: &mut Formatter<'_>, sign: Option<char>, prefix: Option<&str>)
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{Foo:<4}"), "Foo ");
-    /// assert_eq!(&format!("{Foo:0>4}"), "0Foo");
+    /// assert_eq!(format!("{Foo:<4}"), "Foo ");
+    /// assert_eq!(format!("{Foo:0>4}"), "0Foo");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn pad(&mut self, s: &str) -> Result {
@@ -1636,8 +1655,8 @@ fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result {
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{Foo}"), "Foo");
-    /// assert_eq!(&format!("{Foo:0>8}"), "Foo");
+    /// assert_eq!(format!("{Foo}"), "Foo");
+    /// assert_eq!(format!("{Foo:0>8}"), "Foo");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn write_str(&mut self, data: &str) -> Result {
@@ -1659,8 +1678,8 @@ pub fn write_str(&mut self, data: &str) -> Result {
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{}", Foo(-1)), "Foo -1");
-    /// assert_eq!(&format!("{:0>8}", Foo(2)), "Foo 2");
+    /// assert_eq!(format!("{}", Foo(-1)), "Foo -1");
+    /// assert_eq!(format!("{:0>8}", Foo(2)), "Foo 2");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result {
@@ -1703,8 +1722,8 @@ pub fn flags(&self) -> u32 {
     /// }
     ///
     /// // We set alignment to the right with ">".
-    /// assert_eq!(&format!("{Foo:G>3}"), "GGG");
-    /// assert_eq!(&format!("{Foo:t>6}"), "tttttt");
+    /// assert_eq!(format!("{Foo:G>3}"), "GGG");
+    /// assert_eq!(format!("{Foo:t>6}"), "tttttt");
     /// ```
     #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
@@ -1738,10 +1757,10 @@ pub fn fill(&self) -> char {
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{Foo:<}"), "left");
-    /// assert_eq!(&format!("{Foo:>}"), "right");
-    /// assert_eq!(&format!("{Foo:^}"), "center");
-    /// assert_eq!(&format!("{Foo}"), "into the void");
+    /// assert_eq!(format!("{Foo:<}"), "left");
+    /// assert_eq!(format!("{Foo:>}"), "right");
+    /// assert_eq!(format!("{Foo:^}"), "center");
+    /// assert_eq!(format!("{Foo}"), "into the void");
     /// ```
     #[must_use]
     #[stable(feature = "fmt_flags_align", since = "1.28.0")]
@@ -1767,7 +1786,7 @@ pub fn align(&self) -> Option<Alignment> {
     ///     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
     ///         if let Some(width) = formatter.width() {
     ///             // If we received a width, we use it
-    ///             write!(formatter, "{:width$}", &format!("Foo({})", self.0), width = width)
+    ///             write!(formatter, "{:width$}", format!("Foo({})", self.0), width = width)
     ///         } else {
     ///             // Otherwise we do nothing special
     ///             write!(formatter, "Foo({})", self.0)
@@ -1775,8 +1794,8 @@ pub fn align(&self) -> Option<Alignment> {
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{:10}", Foo(23)), "Foo(23)   ");
-    /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
+    /// assert_eq!(format!("{:10}", Foo(23)), "Foo(23)   ");
+    /// assert_eq!(format!("{}", Foo(23)), "Foo(23)");
     /// ```
     #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
@@ -1806,8 +1825,8 @@ pub fn width(&self) -> Option<usize> {
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{:.4}", Foo(23.2)), "Foo(23.2000)");
-    /// assert_eq!(&format!("{}", Foo(23.2)), "Foo(23.20)");
+    /// assert_eq!(format!("{:.4}", Foo(23.2)), "Foo(23.2000)");
+    /// assert_eq!(format!("{}", Foo(23.2)), "Foo(23.20)");
     /// ```
     #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
@@ -1837,9 +1856,9 @@ pub fn precision(&self) -> Option<usize> {
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)");
-    /// assert_eq!(&format!("{:+}", Foo(-23)), "Foo(-23)");
-    /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
+    /// assert_eq!(format!("{:+}", Foo(23)), "Foo(+23)");
+    /// assert_eq!(format!("{:+}", Foo(-23)), "Foo(-23)");
+    /// assert_eq!(format!("{}", Foo(23)), "Foo(23)");
     /// ```
     #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
@@ -1867,8 +1886,8 @@ pub fn sign_plus(&self) -> bool {
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{:-}", Foo(23)), "-Foo(23)");
-    /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
+    /// assert_eq!(format!("{:-}", Foo(23)), "-Foo(23)");
+    /// assert_eq!(format!("{}", Foo(23)), "Foo(23)");
     /// ```
     #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
@@ -1895,8 +1914,8 @@ pub fn sign_minus(&self) -> bool {
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{:#}", Foo(23)), "Foo(23)");
-    /// assert_eq!(&format!("{}", Foo(23)), "23");
+    /// assert_eq!(format!("{:#}", Foo(23)), "Foo(23)");
+    /// assert_eq!(format!("{}", Foo(23)), "23");
     /// ```
     #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
@@ -1922,7 +1941,7 @@ pub fn alternate(&self) -> bool {
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{:04}", Foo(23)), "23");
+    /// assert_eq!(format!("{:04}", Foo(23)), "23");
     /// ```
     #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
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 5bfe001de46e3775f456a9c42c026b0b4230e253..c4fb362094664196a354070a1a8a246062734959 100644 (file)
@@ -112,6 +112,10 @@ pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
     unsafe { &mut *cx.0.as_ptr().cast() }
 }
 
+// FIXME(swatinem): This fn is currently needed to work around shortcomings
+// in type and lifetime inference.
+// See the comment at the bottom of `LoweringContext::make_async_expr` and
+// <https://github.com/rust-lang/rust/issues/104826>.
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
 #[inline]
index e8d724ab1ef4eed662ac5ab2810878e6ee8e2904..5a76e866923366e8716afeb1ddeb3ecc1e470ac7 100644 (file)
@@ -219,6 +219,75 @@ pub fn spin_loop() {
 /// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
 ///
 /// [`std::convert::identity`]: crate::convert::identity
+///
+/// # When is this useful?
+///
+/// First and foremost: `black_box` does _not_ guarantee any exact behavior and, in some cases, may
+/// do nothing at all. As such, it **must not be relied upon to control critical program behavior.**
+/// This _immediately_ precludes any direct use of this function for cryptographic or security
+/// purposes.
+///
+/// While not suitable in those mission-critical cases, `back_box`'s functionality can generally be
+/// relied upon for benchmarking, and should be used there. It will try to ensure that the
+/// compiler doesn't optimize away part of the intended test code based on context. For
+/// example:
+///
+/// ```
+/// fn contains(haystack: &[&str], needle: &str) -> bool {
+///     haystack.iter().any(|x| x == &needle)
+/// }
+///
+/// pub fn benchmark() {
+///     let haystack = vec!["abc", "def", "ghi", "jkl", "mno"];
+///     let needle = "ghi";
+///     for _ in 0..10 {
+///         contains(&haystack, needle);
+///     }
+/// }
+/// ```
+///
+/// The compiler could theoretically make optimizations like the following:
+///
+/// - `needle` and `haystack` are always the same, move the call to `contains` outside the loop and
+///   delete the loop
+/// - Inline `contains`
+/// - `needle` and `haystack` have values known at compile time, `contains` is always true. Remove
+///   the call and replace with `true`
+/// - Nothing is done with the result of `contains`: delete this function call entirely
+/// - `benchmark` now has no purpose: delete this function
+///
+/// It is not likely that all of the above happens, but the compiler is definitely able to make some
+/// optimizations that could result in a very inaccurate benchmark. This is where `black_box` comes
+/// in:
+///
+/// ```
+/// use std::hint::black_box;
+///
+/// // Same `contains` function
+/// fn contains(haystack: &[&str], needle: &str) -> bool {
+///     haystack.iter().any(|x| x == &needle)
+/// }
+///
+/// pub fn benchmark() {
+///     let haystack = vec!["abc", "def", "ghi", "jkl", "mno"];
+///     let needle = "ghi";
+///     for _ in 0..10 {
+///         // Adjust our benchmark loop contents
+///         black_box(contains(black_box(&haystack), black_box(needle)));
+///     }
+/// }
+/// ```
+///
+/// This essentially tells the compiler to block optimizations across any calls to `black_box`. So,
+/// it now:
+///
+/// - Treats both arguments to `contains` as unpredictable: the body of `contains` can no longer be
+///   optimized based on argument values
+/// - Treats the call to `contains` and its result as volatile: the body of `benchmark` cannot
+///   optimize this away
+///
+/// This makes our benchmark much more realistic to how the function would be used in situ, where
+/// arguments are usually not known at compile time and the result is used in some way.
 #[inline]
 #[stable(feature = "bench_black_box", since = "1.66.0")]
 #[rustc_const_unstable(feature = "const_black_box", issue = "none")]
index 399d54f18c5b3803b7b4d3fc69da33dccbf8e692..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
 //!
@@ -259,6 +262,11 @@ pub fn $($sig)* { panic!() }
 define!("mir_drop", fn Drop<T>(place: T, goto: BasicBlock));
 define!("mir_drop_and_replace", fn DropAndReplace<T>(place: T, value: T, goto: BasicBlock));
 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 e0d665c9e12ba0e2465197f0f642d01e1ea23710..6bdf53f7fc9dd8a0d0a0ced46f5dd9ea2941bf7d 100644 (file)
@@ -99,7 +99,7 @@ fn find<T, B>(
         ) -> impl FnMut((), T) -> ControlFlow<B> + '_ {
             move |(), x| match f(x) {
                 Some(x) => ControlFlow::Break(x),
-                None => ControlFlow::CONTINUE,
+                None => ControlFlow::Continue(()),
             }
         }
 
index 307016c269099cf7d4d74981711e8fbe79763059..b040a0ea9011bb88ae1fc35fe153367be3eec980 100644 (file)
@@ -539,7 +539,7 @@ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
         #[rustc_inherit_overflow_checks]
         fn advance<U: Iterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
             match iter.advance_by(n) {
-                Ok(()) => ControlFlow::BREAK,
+                Ok(()) => ControlFlow::Break(()),
                 Err(advanced) => ControlFlow::Continue(n - advanced),
             }
         }
@@ -629,7 +629,7 @@ fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
         #[rustc_inherit_overflow_checks]
         fn advance<U: DoubleEndedIterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
             match iter.advance_back_by(n) {
-                Ok(()) => ControlFlow::BREAK,
+                Ok(()) => ControlFlow::Break(()),
                 Err(advanced) => ControlFlow::Continue(n - advanced),
             }
         }
index ac7b389b15b4d5e9e00e99ef2a4740a7c51b2971..b5739f2f3c0b057d286ecff2095d80f861c5ca18 100644 (file)
@@ -756,7 +756,7 @@ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
     where
         Self: TrustedRandomAccessNoCoerce,
     {
-        // SAFETY: The TrustedRandomAccess contract requires that callers only  pass an index
+        // SAFETY: The TrustedRandomAccess contract requires that callers only pass an index
         // that is in bounds.
         // Additionally Self: TrustedRandomAccess is only implemented for Copy types
         // which means even repeated reads of the same index would be safe.
index 8e7cbd34a4f664b6c1496d6fa65591ca11ce8537..4cbe731b222f920131e999b0bd409747aa387a88 100644 (file)
@@ -1,3 +1,4 @@
+use crate::fmt;
 use crate::ops::{Generator, GeneratorState};
 use crate::pin::Pin;
 
 /// ```
 #[inline]
 #[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
-pub fn from_generator<G: Generator<Return = ()> + Unpin>(
-    generator: G,
-) -> impl Iterator<Item = G::Yield> {
+pub fn from_generator<G: Generator<Return = ()> + Unpin>(generator: G) -> FromGenerator<G> {
     FromGenerator(generator)
 }
 
-struct FromGenerator<G>(G);
+/// An iterator over the values yielded by an underlying generator.
+///
+/// This `struct` is created by the [`iter::from_generator()`] function. See its documentation for
+/// more.
+///
+/// [`iter::from_generator()`]: from_generator
+#[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
+#[derive(Clone)]
+pub struct FromGenerator<G>(G);
 
+#[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
 impl<G: Generator<Return = ()> + Unpin> Iterator for FromGenerator<G> {
     type Item = G::Yield;
 
@@ -41,3 +49,10 @@ fn next(&mut self) -> Option<Self::Item> {
         }
     }
 }
+
+#[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
+impl<G> fmt::Debug for FromGenerator<G> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("FromGenerator").finish()
+    }
+}
index bdf94c792c27c34a3742392440ea53cb7e4adeda..ed23873cdde7cc7e0ae7232504265d5494b96842 100644 (file)
@@ -352,7 +352,7 @@ fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
         #[inline]
         fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow<T> {
             move |(), x| {
-                if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE }
+                if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(()) }
             }
         }
 
index a4a665d48d58cfa15cade9488137e37e2d0d248c..5a0b8594104ee1d1d5e120f5704539205d8bf946 100644 (file)
@@ -2601,10 +2601,10 @@ fn all<F>(&mut self, f: F) -> bool
         #[inline]
         fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<()> {
             move |(), x| {
-                if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK }
+                if f(x) { ControlFlow::Continue(()) } else { ControlFlow::Break(()) }
             }
         }
-        self.try_fold((), check(f)) == ControlFlow::CONTINUE
+        self.try_fold((), check(f)) == ControlFlow::Continue(())
     }
 
     /// Tests if any element of the iterator matches a predicate.
@@ -2654,11 +2654,11 @@ fn any<F>(&mut self, f: F) -> bool
         #[inline]
         fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<()> {
             move |(), x| {
-                if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE }
+                if f(x) { ControlFlow::Break(()) } else { ControlFlow::Continue(()) }
             }
         }
 
-        self.try_fold((), check(f)) == ControlFlow::BREAK
+        self.try_fold((), check(f)) == ControlFlow::Break(())
     }
 
     /// Searches for an element of an iterator that satisfies a predicate.
@@ -2717,7 +2717,7 @@ fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
         #[inline]
         fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow<T> {
             move |(), x| {
-                if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE }
+                if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(()) }
             }
         }
 
@@ -2749,7 +2749,7 @@ fn find_map<B, F>(&mut self, f: F) -> Option<B>
         fn check<T, B>(mut f: impl FnMut(T) -> Option<B>) -> impl FnMut((), T) -> ControlFlow<B> {
             move |(), x| match f(x) {
                 Some(x) => ControlFlow::Break(x),
-                None => ControlFlow::CONTINUE,
+                None => ControlFlow::Continue(()),
             }
         }
 
@@ -2812,7 +2812,7 @@ fn check<I, V, R>(
             R: Residual<Option<I>>,
         {
             move |(), x| match f(&x).branch() {
-                ControlFlow::Continue(false) => ControlFlow::CONTINUE,
+                ControlFlow::Continue(false) => ControlFlow::Continue(()),
                 ControlFlow::Continue(true) => ControlFlow::Break(Try::from_output(Some(x))),
                 ControlFlow::Break(r) => ControlFlow::Break(FromResidual::from_residual(r)),
             }
@@ -3491,7 +3491,7 @@ fn compare<X, Y, F>(mut cmp: F) -> impl FnMut(X, Y) -> ControlFlow<Ordering>
             F: FnMut(X, Y) -> Ordering,
         {
             move |x, y| match cmp(x, y) {
-                Ordering::Equal => ControlFlow::CONTINUE,
+                Ordering::Equal => ControlFlow::Continue(()),
                 non_eq => ControlFlow::Break(non_eq),
             }
         }
@@ -3567,7 +3567,7 @@ fn compare<X, Y, F>(mut partial_cmp: F) -> impl FnMut(X, Y) -> ControlFlow<Optio
             F: FnMut(X, Y) -> Option<Ordering>,
         {
             move |x, y| match partial_cmp(x, y) {
-                Some(Ordering::Equal) => ControlFlow::CONTINUE,
+                Some(Ordering::Equal) => ControlFlow::Continue(()),
                 non_eq => ControlFlow::Break(non_eq),
             }
         }
@@ -3625,7 +3625,7 @@ fn compare<X, Y, F>(mut eq: F) -> impl FnMut(X, Y) -> ControlFlow<()>
             F: FnMut(X, Y) -> bool,
         {
             move |x, y| {
-                if eq(x, y) { ControlFlow::CONTINUE } else { ControlFlow::BREAK }
+                if eq(x, y) { ControlFlow::Continue(()) } else { ControlFlow::Break(()) }
             }
         }
 
@@ -3859,7 +3859,7 @@ unsafe fn __iterator_get_unchecked(&mut self, _idx: usize) -> Self::Item
 
 /// Compares two iterators element-wise using the given function.
 ///
-/// If `ControlFlow::CONTINUE` is returned from the function, the comparison moves on to the next
+/// If `ControlFlow::Continue(())` is returned from the function, the comparison moves on to the next
 /// elements of both iterators. Returning `ControlFlow::Break(x)` short-circuits the iteration and
 /// returns `ControlFlow::Break(x)`. If one of the iterators runs out of elements,
 /// `ControlFlow::Continue(ord)` is returned where `ord` is the result of comparing the lengths of
index 8790649abe6f1b90433171f95816072ecd05a4ca..6dfe36e6926ef057759d23d198abd83910688ada 100644 (file)
@@ -95,6 +95,7 @@
 #![warn(missing_docs)]
 #![allow(explicit_outlives_requirements)]
 #![allow(incomplete_features)]
+#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))]
 //
 // Library features:
 #![feature(const_align_offset)]
 #![feature(unsized_fn_params)]
 #![feature(asm_const)]
 #![feature(const_transmute_copy)]
+#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))]
 //
 // Target features:
 #![feature(arm_target_feature)]
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 ec5fa45fdaddd72489d612d87617c14ed7ce8012..3806977f70ee4598d6a78aa88483b10086460b36 100644 (file)
@@ -26,7 +26,7 @@ mod fpu_precision {
     /// Developer's Manual (Volume 1).
     ///
     /// The only field which is relevant for the following code is PC, Precision Control. This
-    /// field determines the precision of the operations performed by the  FPU. It can be set to:
+    /// field determines the precision of the operations performed by the FPU. It can be set to:
     ///  - 0b00, single precision i.e., 32-bits
     ///  - 0b10, double precision i.e., 64-bits
     ///  - 0b11, double extended precision i.e., 80-bits (default state)
index 21518a3f551807356dbbf2dc484f4af1387490fc..acd0fea4bc4105a03a1d793098e0a45a866a5166 100644 (file)
@@ -1538,7 +1538,7 @@ pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
         ///
         /// ```
         /// #![feature(bigint_helper_methods)]
-        /// // Only the  most significant word is signed.
+        /// // Only the most significant word is signed.
         /// //
         #[doc = concat!("//   10  MAX    (a = 10 × 2^", stringify!($BITS), " + 2^", stringify!($BITS), " - 1)")]
         #[doc = concat!("// + -5    9    (b = -5 × 2^", stringify!($BITS), " + 9)")]
@@ -1625,7 +1625,7 @@ pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
         /// overflow.
         ///
         /// Performs "ternary subtraction" by subtracting both an integer
-        /// operandand a borrow-in bit from `self`, and returns a tuple of the
+        /// operand and a borrow-in bit from `self`, and returns a tuple of the
         /// difference along with a boolean indicating whether an arithmetic
         /// overflow would occur. On overflow, the wrapped value is returned.
         ///
@@ -1646,7 +1646,7 @@ pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
         ///
         /// ```
         /// #![feature(bigint_helper_methods)]
-        /// // Only the  most significant word is signed.
+        /// // Only the most significant word is signed.
         /// //
         #[doc = concat!("//    6    8    (a = 6 × 2^", stringify!($BITS), " + 8)")]
         #[doc = concat!("// - -5    9    (b = -5 × 2^", stringify!($BITS), " + 9)")]
@@ -2574,12 +2574,13 @@ pub const fn abs_diff(self, other: Self) -> $UnsignedT {
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline(always)]
+        #[rustc_allow_const_fn_unstable(const_cmp)]
         pub const fn signum(self) -> Self {
-            match self {
-                n if n > 0 =>  1,
-                0          =>  0,
-                _          => -1,
-            }
+            // Picking the right way to phrase this is complicated
+            // (<https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>)
+            // so delegate it to `Ord` which is already producing -1/0/+1
+            // exactly like we need and can be the place to deal with the complexity.
+            self.cmp(&0) as _
         }
 
         /// Returns `true` if `self` is positive and `false` if the number is zero or
index cd183540cd5e9d3c5d20d2e4d12156a7502571c5..117706fb4b28d3379bf1d8176a4cf9bbc2832018 100644 (file)
@@ -259,46 +259,3 @@ pub(crate) fn into_try(self) -> R {
         }
     }
 }
-
-impl<B> ControlFlow<B, ()> {
-    /// It's frequently the case that there's no value needed with `Continue`,
-    /// so this provides a way to avoid typing `(())`, if you prefer it.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(control_flow_enum)]
-    /// use std::ops::ControlFlow;
-    ///
-    /// let mut partial_sum = 0;
-    /// let last_used = (1..10).chain(20..25).try_for_each(|x| {
-    ///     partial_sum += x;
-    ///     if partial_sum > 100 { ControlFlow::Break(x) }
-    ///     else { ControlFlow::CONTINUE }
-    /// });
-    /// assert_eq!(last_used.break_value(), Some(22));
-    /// ```
-    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
-    pub const CONTINUE: Self = ControlFlow::Continue(());
-}
-
-impl<C> ControlFlow<(), C> {
-    /// APIs like `try_for_each` don't need values with `Break`,
-    /// so this provides a way to avoid typing `(())`, if you prefer it.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(control_flow_enum)]
-    /// use std::ops::ControlFlow;
-    ///
-    /// let mut partial_sum = 0;
-    /// (1..10).chain(20..25).try_for_each(|x| {
-    ///     if partial_sum > 100 { ControlFlow::BREAK }
-    ///     else { partial_sum += x; ControlFlow::CONTINUE }
-    /// });
-    /// assert_eq!(partial_sum, 108);
-    /// ```
-    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
-    pub const BREAK: Self = ControlFlow::Break(());
-}
index 7cc00e3f8d1b7205b3e470b8302d52bcc8ddaba4..c43b728022d2fa60ab35b41f249c33410d3afef0 100644 (file)
 use crate::panicking::{panic, panic_str};
 use crate::pin::Pin;
 use crate::{
-    convert, hint, mem,
+    cmp, convert, hint, mem,
     ops::{self, ControlFlow, Deref, DerefMut},
 };
 
@@ -2090,6 +2090,12 @@ fn eq(&self, other: &Self) -> bool {
     }
 }
 
+/// This specialization trait is a workaround for LLVM not currently (2023-01)
+/// being able to optimize this itself, even though Alive confirms that it would
+/// be legal to do so: <https://github.com/llvm/llvm-project/issues/52622>
+///
+/// Once that's fixed, `Option` should go back to deriving `PartialEq`, as
+/// it used to do before <https://github.com/rust-lang/rust/pull/103556>.
 #[unstable(feature = "spec_option_partial_eq", issue = "none", reason = "exposed only for rustc")]
 #[doc(hidden)]
 pub trait SpecOptionPartialEq: Sized {
@@ -2146,6 +2152,14 @@ fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl SpecOptionPartialEq for cmp::Ordering {
+    #[inline]
+    fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
+        l.map_or(2, |x| x as i8) == r.map_or(2, |x| x as i8)
+    }
+}
+
 /////////////////////////////////////////////////////////////////////////////
 // The Option Iterators
 /////////////////////////////////////////////////////////////////////////////
index 2eb29d4f9c57410081309ed539b6c6f2fb34d1ac..ec0c9984841e68089536f9836cfe70e5bb7dcd81 100644 (file)
@@ -753,7 +753,7 @@ pub fn set(&mut self, value: P::Target)
 impl<'a, T: ?Sized> Pin<&'a T> {
     /// Constructs a new pin by mapping the interior value.
     ///
-    /// For example, if you  wanted to get a `Pin` of a field of something,
+    /// For example, if you wanted to get a `Pin` of a field of something,
     /// you could use this to get access to that field in one line of code.
     /// However, there are several gotchas with these "pinning projections";
     /// see the [`pin` module] documentation for further details on that topic.
@@ -856,7 +856,7 @@ pub const fn get_mut(self) -> &'a mut T
 
     /// Construct a new pin by mapping the interior value.
     ///
-    /// For example, if you  wanted to get a `Pin` of a field of something,
+    /// For example, if you wanted to get a `Pin` of a field of something,
     /// you could use this to get access to that field in one line of code.
     /// However, there are several gotchas with these "pinning projections";
     /// see the [`pin` module] documentation for further details on that topic.
index 0a74c03d70f3a6cf17c95e9a059d49f2960f0945..16eb726f6f61476294d3271abdbd21d4c3b00602 100644 (file)
@@ -202,14 +202,11 @@ pub fn from_bits(bits: usize) -> Self
     #[must_use]
     #[inline(always)]
     #[unstable(feature = "strict_provenance", issue = "95228")]
-    pub fn addr(self) -> usize
-    where
-        T: Sized,
-    {
+    pub fn addr(self) -> usize {
         // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
         // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the
         // provenance).
-        unsafe { mem::transmute(self) }
+        unsafe { mem::transmute(self.cast::<()>()) }
     }
 
     /// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future
@@ -239,12 +236,9 @@ pub fn addr(self) -> usize
     #[must_use]
     #[inline(always)]
     #[unstable(feature = "strict_provenance", issue = "95228")]
-    pub fn expose_addr(self) -> usize
-    where
-        T: Sized,
-    {
+    pub fn expose_addr(self) -> usize {
         // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
-        self as usize
+        self.cast::<()>() as usize
     }
 
     /// Creates a new pointer with the given address.
@@ -262,10 +256,7 @@ pub fn expose_addr(self) -> usize
     #[must_use]
     #[inline]
     #[unstable(feature = "strict_provenance", issue = "95228")]
-    pub fn with_addr(self, addr: usize) -> Self
-    where
-        T: Sized,
-    {
+    pub fn with_addr(self, addr: usize) -> Self {
         // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
         //
         // In the mean-time, this operation is defined to be "as if" it was
@@ -288,10 +279,7 @@ pub fn with_addr(self, addr: usize) -> Self
     #[must_use]
     #[inline]
     #[unstable(feature = "strict_provenance", issue = "95228")]
-    pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self
-    where
-        T: Sized,
-    {
+    pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self {
         self.with_addr(f(self.addr()))
     }
 
@@ -743,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 5f30029eaa07d5c8d9be41bd6a6f221e13b0b43e..1ad9af1549a47fcdf12e46b391e12891c2fba0bd 100644 (file)
@@ -1701,7 +1701,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
         // offset is not a multiple of `stride`, the input pointer was misaligned and no pointer
         // offset will be able to produce a `p` aligned to the specified `a`.
         //
-        // The naive `-p (mod a)` equation  inhibits LLVM's ability to select instructions
+        // The naive `-p (mod a)` equation inhibits LLVM's ability to select instructions
         // like `lea`. We compute `(round_up_to_next_alignment(p, a) - p)` instead. This
         // redistributes operations around the load-bearing, but pessimizing `and` instruction
         // sufficiently for LLVM to be able to utilize the various optimizations it knows about.
index d70fb70c79fa4dc6dacc84297e67a062235bd8d8..0a2f63e3ec6a5fb1ecce6845f442790d1cfa7c4d 100644 (file)
@@ -208,14 +208,11 @@ pub fn from_bits(bits: usize) -> Self
     #[must_use]
     #[inline(always)]
     #[unstable(feature = "strict_provenance", issue = "95228")]
-    pub fn addr(self) -> usize
-    where
-        T: Sized,
-    {
+    pub fn addr(self) -> usize {
         // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
         // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the
         // provenance).
-        unsafe { mem::transmute(self) }
+        unsafe { mem::transmute(self.cast::<()>()) }
     }
 
     /// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future
@@ -245,12 +242,9 @@ pub fn addr(self) -> usize
     #[must_use]
     #[inline(always)]
     #[unstable(feature = "strict_provenance", issue = "95228")]
-    pub fn expose_addr(self) -> usize
-    where
-        T: Sized,
-    {
+    pub fn expose_addr(self) -> usize {
         // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
-        self as usize
+        self.cast::<()>() as usize
     }
 
     /// Creates a new pointer with the given address.
@@ -268,10 +262,7 @@ pub fn expose_addr(self) -> usize
     #[must_use]
     #[inline]
     #[unstable(feature = "strict_provenance", issue = "95228")]
-    pub fn with_addr(self, addr: usize) -> Self
-    where
-        T: Sized,
-    {
+    pub fn with_addr(self, addr: usize) -> Self {
         // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
         //
         // In the mean-time, this operation is defined to be "as if" it was
@@ -294,10 +285,7 @@ pub fn with_addr(self, addr: usize) -> Self
     #[must_use]
     #[inline]
     #[unstable(feature = "strict_provenance", issue = "95228")]
-    pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self
-    where
-        T: Sized,
-    {
+    pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self {
         self.with_addr(f(self.addr()))
     }
 
@@ -916,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 af79d4bbd836c027e8037ed1808afd6e762b07d6..8c1a648860555bacacf1d8b9d7cce1e621f08cc0 100644 (file)
@@ -268,10 +268,7 @@ pub const fn to_raw_parts(self) -> (NonNull<()>, <T as super::Pointee>::Metadata
     #[must_use]
     #[inline]
     #[unstable(feature = "strict_provenance", issue = "95228")]
-    pub fn addr(self) -> NonZeroUsize
-    where
-        T: Sized,
-    {
+    pub fn addr(self) -> NonZeroUsize {
         // SAFETY: The pointer is guaranteed by the type to be non-null,
         // meaning that the address will be non-zero.
         unsafe { NonZeroUsize::new_unchecked(self.pointer.addr()) }
@@ -286,10 +283,7 @@ pub fn addr(self) -> NonZeroUsize
     #[must_use]
     #[inline]
     #[unstable(feature = "strict_provenance", issue = "95228")]
-    pub fn with_addr(self, addr: NonZeroUsize) -> Self
-    where
-        T: Sized,
-    {
+    pub fn with_addr(self, addr: NonZeroUsize) -> Self {
         // SAFETY: The result of `ptr::from::with_addr` is non-null because `addr` is guaranteed to be non-zero.
         unsafe { NonNull::new_unchecked(self.pointer.with_addr(addr.get()) as *mut _) }
     }
@@ -303,10 +297,7 @@ pub fn with_addr(self, addr: NonZeroUsize) -> Self
     #[must_use]
     #[inline]
     #[unstable(feature = "strict_provenance", issue = "95228")]
-    pub fn map_addr(self, f: impl FnOnce(NonZeroUsize) -> NonZeroUsize) -> Self
-    where
-        T: Sized,
-    {
+    pub fn map_addr(self, f: impl FnOnce(NonZeroUsize) -> NonZeroUsize) -> Self {
         self.with_addr(f(self.addr()))
     }
 
index 06228976719f52f8e25c59010c4fab554b7ae4f5..90ab43d1289f0d22b3b2dcfecc81ccb5e71bdc88 100644 (file)
@@ -6,7 +6,7 @@
 use crate::cmp;
 use crate::cmp::Ordering;
 use crate::fmt;
-use crate::intrinsics::{assume, exact_div, unchecked_sub};
+use crate::intrinsics::assume;
 use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
 use crate::marker::{PhantomData, Send, Sized, Sync};
 use crate::mem::{self, SizedTypeProperties};
@@ -35,12 +35,6 @@ fn into_iter(self) -> IterMut<'a, T> {
     }
 }
 
-// Macro helper functions
-#[inline(always)]
-fn size_from_ptr<T>(_: *const T) -> usize {
-    mem::size_of::<T>()
-}
-
 /// Immutable slice iterator
 ///
 /// This struct is created by the [`iter`] method on [slices].
@@ -65,7 +59,7 @@ fn size_from_ptr<T>(_: *const T) -> usize {
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub struct Iter<'a, T: 'a> {
     ptr: NonNull<T>,
-    end: *const T, // If T is a ZST, this is actually ptr+len.  This encoding is picked so that
+    end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
     // ptr == end is a quick test for the Iterator being empty, that works
     // for both ZST and non-ZST.
     _marker: PhantomData<&'a T>,
@@ -186,7 +180,7 @@ fn as_ref(&self) -> &[T] {
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub struct IterMut<'a, T: 'a> {
     ptr: NonNull<T>,
-    end: *mut T, // If T is a ZST, this is actually ptr+len.  This encoding is picked so that
+    end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
     // ptr == end is a quick test for the Iterator being empty, that works
     // for both ZST and non-ZST.
     _marker: PhantomData<&'a mut T>,
index ce51d48e3e551901457c3af8d9783f9c544e2af5..0fd57b197aa97daa8838687de60165d6d3518372 100644 (file)
@@ -9,30 +9,20 @@ macro_rules! is_empty {
     };
 }
 
-// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
-// unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
 macro_rules! len {
     ($self: ident) => {{
         #![allow(unused_unsafe)] // we're sometimes used within an unsafe block
 
         let start = $self.ptr;
-        let size = size_from_ptr(start.as_ptr());
-        if size == 0 {
-            // This _cannot_ use `unchecked_sub` because we depend on wrapping
+        if T::IS_ZST {
+            // This _cannot_ use `ptr_sub` because we depend on wrapping
             // to represent the length of long ZST slice iterators.
             $self.end.addr().wrapping_sub(start.as_ptr().addr())
         } else {
-            // We know that `start <= end`, so can do better than `offset_from`,
-            // which needs to deal in signed.  By setting appropriate flags here
-            // we can tell LLVM this, which helps it remove bounds checks.
-            // SAFETY: By the type invariant, `start <= end`
-            let diff = unsafe { unchecked_sub($self.end.addr(), start.as_ptr().addr()) };
-            // By also telling LLVM that the pointers are apart by an exact
-            // multiple of the type size, it can optimize `len() == 0` down to
-            // `start == end` instead of `(end - start) < size`.
-            // SAFETY: By the type invariant, the pointers are aligned so the
-            //         distance between them must be a multiple of pointee size
-            unsafe { exact_div(diff, size) }
+            // To get rid of some bounds checks (see `position`), we use ptr_sub instead of
+            // offset_from (Tested by `codegen/slice-position-bounds-check`.)
+            // SAFETY: by the type invariant pointers are aligned and `start <= end`
+            unsafe { $self.end.sub_ptr(start.as_ptr()) }
         }
     }};
 }
index 2995cf0c6443f8a03eb37ae1201a0ecffeb1b272..d93a3a57ecd27fdcdb94a4aa479a5e8ceb02be3c 100644 (file)
 /// Pure rust memchr implementation, taken from rust-memchr
 pub mod memchr;
 
+#[unstable(
+    feature = "slice_internals",
+    issue = "none",
+    reason = "exposed from core to be reused in std;"
+)]
+pub mod sort;
+
 mod ascii;
 mod cmp;
 mod index;
 mod iter;
 mod raw;
 mod rotate;
-mod sort;
 mod specialize;
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -703,7 +709,7 @@ const fn revswap<T>(a: &mut [T], b: &mut [T], n: usize) {
 
             // Because this function is first compiled in isolation,
             // this check tells LLVM that the indexing below is
-            // in-bounds.  Then after inlining -- once the actual
+            // in-bounds. Then after inlining -- once the actual
             // lengths of the slices are known -- it's removed.
             let (a, b) = (&mut a[..n], &mut b[..n]);
 
@@ -781,6 +787,22 @@ pub fn iter_mut(&mut self) -> IterMut<'_, T> {
     /// let mut iter = slice.windows(4);
     /// assert!(iter.next().is_none());
     /// ```
+    ///
+    /// There's no `windows_mut`, as that existing would let safe code violate the
+    /// "only one `&mut` at a time to the same thing" rule.  However, you can sometimes
+    /// use [`Cell::as_slice_of_cells`](crate::cell::Cell::as_slice_of_cells) in
+    /// conjunction with `windows` to accomplish something similar:
+    /// ```
+    /// use std::cell::Cell;
+    ///
+    /// let mut array = ['R', 'u', 's', 't', ' ', '2', '0', '1', '5'];
+    /// let slice = &mut array[..];
+    /// let slice_of_cells: &[Cell<char>] = Cell::from_mut(slice).as_slice_of_cells();
+    /// for w in slice_of_cells.windows(3) {
+    ///     Cell::swap(&w[0], &w[2]);
+    /// }
+    /// assert_eq!(array, ['s', 't', ' ', '2', '0', '1', '5', 'u', 'R']);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn windows(&self, size: usize) -> Windows<'_, T> {
@@ -1248,7 +1270,7 @@ pub fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N> {
         ArrayChunksMut::new(self)
     }
 
-    /// Returns an iterator over overlapping windows of `N` elements of  a slice,
+    /// Returns an iterator over overlapping windows of `N` elements of a slice,
     /// starting at the beginning of the slice.
     ///
     /// This is the const generic equivalent of [`windows`].
@@ -2476,7 +2498,7 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
             let mid = left + size / 2;
 
             // SAFETY: the while condition means `size` is strictly positive, so
-            // `size/2 < size`.  Thus `left + size/2 < left + size`, which
+            // `size/2 < size`. Thus `left + size/2 < left + size`, which
             // coupled with the `left + size <= self.len()` invariant means
             // we have `left + size/2 < self.len()`, and this is in-bounds.
             let cmp = f(unsafe { self.get_unchecked(mid) });
index b8c0c3fd9493285b10117fb8ede4d341ee733607..2181f9a811855f7ac2a39352b481f0f865e193d5 100644 (file)
@@ -5,6 +5,9 @@
 //!
 //! Unstable sorting is compatible with core because it doesn't allocate memory, unlike our
 //! stable sorting implementation.
+//!
+//! In addition it also contains the core logic of the stable sort used by `slice::sort` based on
+//! TimSort.
 
 use crate::cmp;
 use crate::mem::{self, MaybeUninit, SizedTypeProperties};
@@ -18,9 +21,9 @@ struct CopyOnDrop<T> {
 
 impl<T> Drop for CopyOnDrop<T> {
     fn drop(&mut self) {
-        // SAFETY:  This is a helper class.
-        //          Please refer to its usage for correctness.
-        //          Namely, one must be sure that `src` and `dst` does not overlap as required by `ptr::copy_nonoverlapping`.
+        // SAFETY: This is a helper class.
+        //         Please refer to its usage for correctness.
+        //         Namely, one must be sure that `src` and `dst` does not overlap as required by `ptr::copy_nonoverlapping`.
         unsafe {
             ptr::copy_nonoverlapping(self.src, self.dest, 1);
         }
@@ -831,6 +834,15 @@ fn partition_at_index_loop<'a, T, F>(
 ) where
     F: FnMut(&T, &T) -> bool,
 {
+    // Limit the amount of iterations and fall back to heapsort, similarly to `slice::sort_unstable`.
+    // This lowers the worst case running time from O(n^2) to O(n log n).
+    // FIXME: Investigate whether it would be better to use something like Median of Medians
+    // or Fast Deterministic Selection to guarantee O(n) worst case.
+    let mut limit = usize::BITS - v.len().leading_zeros();
+
+    // True if the last partitioning was reasonably balanced.
+    let mut was_balanced = true;
+
     loop {
         // For slices of up to this length it's probably faster to simply sort them.
         const MAX_INSERTION: usize = 10;
@@ -839,6 +851,18 @@ fn partition_at_index_loop<'a, T, F>(
             return;
         }
 
+        if limit == 0 {
+            heapsort(v, is_less);
+            return;
+        }
+
+        // If the last partitioning was imbalanced, try breaking patterns in the slice by shuffling
+        // some elements around. Hopefully we'll choose a better pivot this time.
+        if !was_balanced {
+            break_patterns(v);
+            limit -= 1;
+        }
+
         // Choose a pivot
         let (pivot, _) = choose_pivot(v, is_less);
 
@@ -863,6 +887,7 @@ fn partition_at_index_loop<'a, T, F>(
         }
 
         let (mid, _) = partition(v, pivot, is_less);
+        was_balanced = cmp::min(mid, v.len() - mid) >= v.len() / 8;
 
         // Split the slice into `left`, `pivot`, and `right`.
         let (left, right) = v.split_at_mut(mid);
@@ -883,6 +908,7 @@ fn partition_at_index_loop<'a, T, F>(
     }
 }
 
+/// Reorder the slice such that the element at `index` is at its final sorted position.
 pub fn partition_at_index<T, F>(
     v: &mut [T],
     index: usize,
@@ -927,3 +953,513 @@ pub fn partition_at_index<T, F>(
     let pivot = &mut pivot[0];
     (left, pivot, right)
 }
+
+/// Inserts `v[0]` into pre-sorted sequence `v[1..]` so that whole `v[..]` becomes sorted.
+///
+/// This is the integral subroutine of insertion sort.
+fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
+where
+    F: FnMut(&T, &T) -> bool,
+{
+    if v.len() >= 2 && is_less(&v[1], &v[0]) {
+        // SAFETY: Copy tmp back even if panic, and ensure unique observation.
+        unsafe {
+            // There are three ways to implement insertion here:
+            //
+            // 1. Swap adjacent elements until the first one gets to its final destination.
+            //    However, this way we copy data around more than is necessary. If elements are big
+            //    structures (costly to copy), this method will be slow.
+            //
+            // 2. Iterate until the right place for the first element is found. Then shift the
+            //    elements succeeding it to make room for it and finally place it into the
+            //    remaining hole. This is a good method.
+            //
+            // 3. Copy the first element into a temporary variable. Iterate until the right place
+            //    for it is found. As we go along, copy every traversed element into the slot
+            //    preceding it. Finally, copy data from the temporary variable into the remaining
+            //    hole. This method is very good. Benchmarks demonstrated slightly better
+            //    performance than with the 2nd method.
+            //
+            // All methods were benchmarked, and the 3rd showed best results. So we chose that one.
+            let tmp = mem::ManuallyDrop::new(ptr::read(&v[0]));
+
+            // Intermediate state of the insertion process is always tracked by `hole`, which
+            // serves two purposes:
+            // 1. Protects integrity of `v` from panics in `is_less`.
+            // 2. Fills the remaining hole in `v` in the end.
+            //
+            // Panic safety:
+            //
+            // If `is_less` panics at any point during the process, `hole` will get dropped and
+            // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it
+            // initially held exactly once.
+            let mut hole = InsertionHole { src: &*tmp, dest: &mut v[1] };
+            ptr::copy_nonoverlapping(&v[1], &mut v[0], 1);
+
+            for i in 2..v.len() {
+                if !is_less(&v[i], &*tmp) {
+                    break;
+                }
+                ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1);
+                hole.dest = &mut v[i];
+            }
+            // `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`.
+        }
+    }
+
+    // When dropped, copies from `src` into `dest`.
+    struct InsertionHole<T> {
+        src: *const T,
+        dest: *mut T,
+    }
+
+    impl<T> Drop for InsertionHole<T> {
+        fn drop(&mut self) {
+            // SAFETY: The caller must ensure that src and dest are correctly set.
+            unsafe {
+                ptr::copy_nonoverlapping(self.src, self.dest, 1);
+            }
+        }
+    }
+}
+
+/// Merges non-decreasing runs `v[..mid]` and `v[mid..]` using `buf` as temporary storage, and
+/// stores the result into `v[..]`.
+///
+/// # Safety
+///
+/// The two slices must be non-empty and `mid` must be in bounds. Buffer `buf` must be long enough
+/// to hold a copy of the shorter slice. Also, `T` must not be a zero-sized type.
+unsafe fn merge<T, F>(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F)
+where
+    F: FnMut(&T, &T) -> bool,
+{
+    let len = v.len();
+    let v = v.as_mut_ptr();
+
+    // SAFETY: mid and len must be in-bounds of v.
+    let (v_mid, v_end) = unsafe { (v.add(mid), v.add(len)) };
+
+    // The merge process first copies the shorter run into `buf`. Then it traces the newly copied
+    // run and the longer run forwards (or backwards), comparing their next unconsumed elements and
+    // copying the lesser (or greater) one into `v`.
+    //
+    // As soon as the shorter run is fully consumed, the process is done. If the longer run gets
+    // consumed first, then we must copy whatever is left of the shorter run into the remaining
+    // hole in `v`.
+    //
+    // Intermediate state of the process is always tracked by `hole`, which serves two purposes:
+    // 1. Protects integrity of `v` from panics in `is_less`.
+    // 2. Fills the remaining hole in `v` if the longer run gets consumed first.
+    //
+    // Panic safety:
+    //
+    // If `is_less` panics at any point during the process, `hole` will get dropped and fill the
+    // hole in `v` with the unconsumed range in `buf`, thus ensuring that `v` still holds every
+    // object it initially held exactly once.
+    let mut hole;
+
+    if mid <= len - mid {
+        // The left run is shorter.
+
+        // SAFETY: buf must have enough capacity for `v[..mid]`.
+        unsafe {
+            ptr::copy_nonoverlapping(v, buf, mid);
+            hole = MergeHole { start: buf, end: buf.add(mid), dest: v };
+        }
+
+        // Initially, these pointers point to the beginnings of their arrays.
+        let left = &mut hole.start;
+        let mut right = v_mid;
+        let out = &mut hole.dest;
+
+        while *left < hole.end && right < v_end {
+            // Consume the lesser side.
+            // If equal, prefer the left run to maintain stability.
+
+            // SAFETY: left and right must be valid and part of v same for out.
+            unsafe {
+                let to_copy = if is_less(&*right, &**left) {
+                    get_and_increment(&mut right)
+                } else {
+                    get_and_increment(left)
+                };
+                ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1);
+            }
+        }
+    } else {
+        // The right run is shorter.
+
+        // SAFETY: buf must have enough capacity for `v[mid..]`.
+        unsafe {
+            ptr::copy_nonoverlapping(v_mid, buf, len - mid);
+            hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid };
+        }
+
+        // Initially, these pointers point past the ends of their arrays.
+        let left = &mut hole.dest;
+        let right = &mut hole.end;
+        let mut out = v_end;
+
+        while v < *left && buf < *right {
+            // Consume the greater side.
+            // If equal, prefer the right run to maintain stability.
+
+            // SAFETY: left and right must be valid and part of v same for out.
+            unsafe {
+                let to_copy = if is_less(&*right.sub(1), &*left.sub(1)) {
+                    decrement_and_get(left)
+                } else {
+                    decrement_and_get(right)
+                };
+                ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1);
+            }
+        }
+    }
+    // Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of
+    // it will now be copied into the hole in `v`.
+
+    unsafe fn get_and_increment<T>(ptr: &mut *mut T) -> *mut T {
+        let old = *ptr;
+
+        // SAFETY: ptr.add(1) must still be a valid pointer and part of `v`.
+        *ptr = unsafe { ptr.add(1) };
+        old
+    }
+
+    unsafe fn decrement_and_get<T>(ptr: &mut *mut T) -> *mut T {
+        // SAFETY: ptr.sub(1) must still be a valid pointer and part of `v`.
+        *ptr = unsafe { ptr.sub(1) };
+        *ptr
+    }
+
+    // When dropped, copies the range `start..end` into `dest..`.
+    struct MergeHole<T> {
+        start: *mut T,
+        end: *mut T,
+        dest: *mut T,
+    }
+
+    impl<T> Drop for MergeHole<T> {
+        fn drop(&mut self) {
+            // SAFETY: `T` is not a zero-sized type, and these are pointers into a slice's elements.
+            unsafe {
+                let len = self.end.sub_ptr(self.start);
+                ptr::copy_nonoverlapping(self.start, self.dest, len);
+            }
+        }
+    }
+}
+
+/// This merge sort borrows some (but not all) ideas from TimSort, which used to be described in
+/// detail [here](https://github.com/python/cpython/blob/main/Objects/listsort.txt). However Python
+/// has switched to a Powersort based implementation.
+///
+/// The algorithm identifies strictly descending and non-descending subsequences, which are called
+/// natural runs. There is a stack of pending runs yet to be merged. Each newly found run is pushed
+/// onto the stack, and then some pairs of adjacent runs are merged until these two invariants are
+/// satisfied:
+///
+/// 1. for every `i` in `1..runs.len()`: `runs[i - 1].len > runs[i].len`
+/// 2. for every `i` in `2..runs.len()`: `runs[i - 2].len > runs[i - 1].len + runs[i].len`
+///
+/// The invariants ensure that the total running time is *O*(*n* \* log(*n*)) worst-case.
+pub fn merge_sort<T, CmpF, ElemAllocF, ElemDeallocF, RunAllocF, RunDeallocF>(
+    v: &mut [T],
+    is_less: &mut CmpF,
+    elem_alloc_fn: ElemAllocF,
+    elem_dealloc_fn: ElemDeallocF,
+    run_alloc_fn: RunAllocF,
+    run_dealloc_fn: RunDeallocF,
+) where
+    CmpF: FnMut(&T, &T) -> bool,
+    ElemAllocF: Fn(usize) -> *mut T,
+    ElemDeallocF: Fn(*mut T, usize),
+    RunAllocF: Fn(usize) -> *mut TimSortRun,
+    RunDeallocF: Fn(*mut TimSortRun, usize),
+{
+    // Slices of up to this length get sorted using insertion sort.
+    const MAX_INSERTION: usize = 20;
+    // Very short runs are extended using insertion sort to span at least this many elements.
+    const MIN_RUN: usize = 10;
+
+    // The caller should have already checked that.
+    debug_assert!(!T::IS_ZST);
+
+    let len = v.len();
+
+    // Short arrays get sorted in-place via insertion sort to avoid allocations.
+    if len <= MAX_INSERTION {
+        if len >= 2 {
+            for i in (0..len - 1).rev() {
+                insert_head(&mut v[i..], is_less);
+            }
+        }
+        return;
+    }
+
+    // Allocate a buffer to use as scratch memory. We keep the length 0 so we can keep in it
+    // shallow copies of the contents of `v` without risking the dtors running on copies if
+    // `is_less` panics. When merging two sorted runs, this buffer holds a copy of the shorter run,
+    // which will always have length at most `len / 2`.
+    let buf = BufGuard::new(len / 2, elem_alloc_fn, elem_dealloc_fn);
+    let buf_ptr = buf.buf_ptr;
+
+    let mut runs = RunVec::new(run_alloc_fn, run_dealloc_fn);
+
+    // In order to identify natural runs in `v`, we traverse it backwards. That might seem like a
+    // strange decision, but consider the fact that merges more often go in the opposite direction
+    // (forwards). According to benchmarks, merging forwards is slightly faster than merging
+    // backwards. To conclude, identifying runs by traversing backwards improves performance.
+    let mut end = len;
+    while end > 0 {
+        // Find the next natural run, and reverse it if it's strictly descending.
+        let mut start = end - 1;
+        if start > 0 {
+            start -= 1;
+
+            // SAFETY: The v.get_unchecked must be fed with correct inbound indicies.
+            unsafe {
+                if is_less(v.get_unchecked(start + 1), v.get_unchecked(start)) {
+                    while start > 0 && is_less(v.get_unchecked(start), v.get_unchecked(start - 1)) {
+                        start -= 1;
+                    }
+                    v[start..end].reverse();
+                } else {
+                    while start > 0 && !is_less(v.get_unchecked(start), v.get_unchecked(start - 1))
+                    {
+                        start -= 1;
+                    }
+                }
+            }
+        }
+
+        // Insert some more elements into the run if it's too short. Insertion sort is faster than
+        // merge sort on short sequences, so this significantly improves performance.
+        while start > 0 && end - start < MIN_RUN {
+            start -= 1;
+            insert_head(&mut v[start..end], is_less);
+        }
+
+        // Push this run onto the stack.
+        runs.push(TimSortRun { start, len: end - start });
+        end = start;
+
+        // Merge some pairs of adjacent runs to satisfy the invariants.
+        while let Some(r) = collapse(runs.as_slice()) {
+            let left = runs[r + 1];
+            let right = runs[r];
+            // SAFETY: `buf_ptr` must hold enough capacity for the shorter of the two sides, and
+            // neither side may be on length 0.
+            unsafe {
+                merge(&mut v[left.start..right.start + right.len], left.len, buf_ptr, is_less);
+            }
+            runs[r] = TimSortRun { start: left.start, len: left.len + right.len };
+            runs.remove(r + 1);
+        }
+    }
+
+    // Finally, exactly one run must remain in the stack.
+    debug_assert!(runs.len() == 1 && runs[0].start == 0 && runs[0].len == len);
+
+    // Examines the stack of runs and identifies the next pair of runs to merge. More specifically,
+    // if `Some(r)` is returned, that means `runs[r]` and `runs[r + 1]` must be merged next. If the
+    // algorithm should continue building a new run instead, `None` is returned.
+    //
+    // TimSort is infamous for its buggy implementations, as described here:
+    // http://envisage-project.eu/timsort-specification-and-verification/
+    //
+    // The gist of the story is: we must enforce the invariants on the top four runs on the stack.
+    // Enforcing them on just top three is not sufficient to ensure that the invariants will still
+    // hold for *all* runs in the stack.
+    //
+    // This function correctly checks invariants for the top four runs. Additionally, if the top
+    // run starts at index 0, it will always demand a merge operation until the stack is fully
+    // collapsed, in order to complete the sort.
+    #[inline]
+    fn collapse(runs: &[TimSortRun]) -> Option<usize> {
+        let n = runs.len();
+        if n >= 2
+            && (runs[n - 1].start == 0
+                || runs[n - 2].len <= runs[n - 1].len
+                || (n >= 3 && runs[n - 3].len <= runs[n - 2].len + runs[n - 1].len)
+                || (n >= 4 && runs[n - 4].len <= runs[n - 3].len + runs[n - 2].len))
+        {
+            if n >= 3 && runs[n - 3].len < runs[n - 1].len { Some(n - 3) } else { Some(n - 2) }
+        } else {
+            None
+        }
+    }
+
+    // Extremely basic versions of Vec.
+    // Their use is super limited and by having the code here, it allows reuse between the sort
+    // implementations.
+    struct BufGuard<T, ElemDeallocF>
+    where
+        ElemDeallocF: Fn(*mut T, usize),
+    {
+        buf_ptr: *mut T,
+        capacity: usize,
+        elem_dealloc_fn: ElemDeallocF,
+    }
+
+    impl<T, ElemDeallocF> BufGuard<T, ElemDeallocF>
+    where
+        ElemDeallocF: Fn(*mut T, usize),
+    {
+        fn new<ElemAllocF>(
+            len: usize,
+            elem_alloc_fn: ElemAllocF,
+            elem_dealloc_fn: ElemDeallocF,
+        ) -> Self
+        where
+            ElemAllocF: Fn(usize) -> *mut T,
+        {
+            Self { buf_ptr: elem_alloc_fn(len), capacity: len, elem_dealloc_fn }
+        }
+    }
+
+    impl<T, ElemDeallocF> Drop for BufGuard<T, ElemDeallocF>
+    where
+        ElemDeallocF: Fn(*mut T, usize),
+    {
+        fn drop(&mut self) {
+            (self.elem_dealloc_fn)(self.buf_ptr, self.capacity);
+        }
+    }
+
+    struct RunVec<RunAllocF, RunDeallocF>
+    where
+        RunAllocF: Fn(usize) -> *mut TimSortRun,
+        RunDeallocF: Fn(*mut TimSortRun, usize),
+    {
+        buf_ptr: *mut TimSortRun,
+        capacity: usize,
+        len: usize,
+        run_alloc_fn: RunAllocF,
+        run_dealloc_fn: RunDeallocF,
+    }
+
+    impl<RunAllocF, RunDeallocF> RunVec<RunAllocF, RunDeallocF>
+    where
+        RunAllocF: Fn(usize) -> *mut TimSortRun,
+        RunDeallocF: Fn(*mut TimSortRun, usize),
+    {
+        fn new(run_alloc_fn: RunAllocF, run_dealloc_fn: RunDeallocF) -> Self {
+            // Most slices can be sorted with at most 16 runs in-flight.
+            const START_RUN_CAPACITY: usize = 16;
+
+            Self {
+                buf_ptr: run_alloc_fn(START_RUN_CAPACITY),
+                capacity: START_RUN_CAPACITY,
+                len: 0,
+                run_alloc_fn,
+                run_dealloc_fn,
+            }
+        }
+
+        fn push(&mut self, val: TimSortRun) {
+            if self.len == self.capacity {
+                let old_capacity = self.capacity;
+                let old_buf_ptr = self.buf_ptr;
+
+                self.capacity = self.capacity * 2;
+                self.buf_ptr = (self.run_alloc_fn)(self.capacity);
+
+                // SAFETY: buf_ptr new and old were correctly allocated and old_buf_ptr has
+                // old_capacity valid elements.
+                unsafe {
+                    ptr::copy_nonoverlapping(old_buf_ptr, self.buf_ptr, old_capacity);
+                }
+
+                (self.run_dealloc_fn)(old_buf_ptr, old_capacity);
+            }
+
+            // SAFETY: The invariant was just checked.
+            unsafe {
+                self.buf_ptr.add(self.len).write(val);
+            }
+            self.len += 1;
+        }
+
+        fn remove(&mut self, index: usize) {
+            if index >= self.len {
+                panic!("Index out of bounds");
+            }
+
+            // SAFETY: buf_ptr needs to be valid and len invariant upheld.
+            unsafe {
+                // the place we are taking from.
+                let ptr = self.buf_ptr.add(index);
+
+                // Shift everything down to fill in that spot.
+                ptr::copy(ptr.add(1), ptr, self.len - index - 1);
+            }
+            self.len -= 1;
+        }
+
+        fn as_slice(&self) -> &[TimSortRun] {
+            // SAFETY: Safe as long as buf_ptr is valid and len invariant was upheld.
+            unsafe { &*ptr::slice_from_raw_parts(self.buf_ptr, self.len) }
+        }
+
+        fn len(&self) -> usize {
+            self.len
+        }
+    }
+
+    impl<RunAllocF, RunDeallocF> core::ops::Index<usize> for RunVec<RunAllocF, RunDeallocF>
+    where
+        RunAllocF: Fn(usize) -> *mut TimSortRun,
+        RunDeallocF: Fn(*mut TimSortRun, usize),
+    {
+        type Output = TimSortRun;
+
+        fn index(&self, index: usize) -> &Self::Output {
+            if index < self.len {
+                // SAFETY: buf_ptr and len invariant must be upheld.
+                unsafe {
+                    return &*(self.buf_ptr.add(index));
+                }
+            }
+
+            panic!("Index out of bounds");
+        }
+    }
+
+    impl<RunAllocF, RunDeallocF> core::ops::IndexMut<usize> for RunVec<RunAllocF, RunDeallocF>
+    where
+        RunAllocF: Fn(usize) -> *mut TimSortRun,
+        RunDeallocF: Fn(*mut TimSortRun, usize),
+    {
+        fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+            if index < self.len {
+                // SAFETY: buf_ptr and len invariant must be upheld.
+                unsafe {
+                    return &mut *(self.buf_ptr.add(index));
+                }
+            }
+
+            panic!("Index out of bounds");
+        }
+    }
+
+    impl<RunAllocF, RunDeallocF> Drop for RunVec<RunAllocF, RunDeallocF>
+    where
+        RunAllocF: Fn(usize) -> *mut TimSortRun,
+        RunDeallocF: Fn(*mut TimSortRun, usize),
+    {
+        fn drop(&mut self) {
+            // As long as TimSortRun is Copy we don't need to drop them individually but just the
+            // whole allocation.
+            (self.run_dealloc_fn)(self.buf_ptr, self.capacity);
+        }
+    }
+}
+
+/// Internal type used by merge_sort.
+#[derive(Clone, Copy, Debug)]
+pub struct TimSortRun {
+    len: usize,
+    start: usize,
+}
index 14367eb09bc75e0e00c13ec9a4025638df8630f0..818721062d7f702aeba8df4096d55fbc6456427e 100644 (file)
@@ -1861,7 +1861,8 @@ macro_rules! if_not_8_bit {
     ($_:ident, $($tt:tt)*) => { $($tt)* };
 }
 
-#[cfg(target_has_atomic_load_store = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic_load_store))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic_load_store = "8"))]
 macro_rules! atomic_int {
     ($cfg_cas:meta,
      $cfg_align:meta,
@@ -2988,7 +2989,8 @@ macro_rules! atomic_int_ptr_sized {
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 fn strongest_failure_ordering(order: Ordering) -> Ordering {
     match order {
         Release => Relaxed,
@@ -3030,7 +3032,8 @@ unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_swap`.
@@ -3047,7 +3050,8 @@ unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// Returns the previous value (like __sync_fetch_and_add).
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_add`.
@@ -3064,7 +3068,8 @@ unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// Returns the previous value (like __sync_fetch_and_sub).
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_sub`.
@@ -3080,7 +3085,8 @@ unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_compare_exchange<T: Copy>(
     dst: *mut T,
@@ -3115,7 +3121,8 @@ unsafe fn atomic_compare_exchange<T: Copy>(
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_compare_exchange_weak<T: Copy>(
     dst: *mut T,
@@ -3150,7 +3157,8 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>(
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_and`
@@ -3166,7 +3174,8 @@ unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_nand`
@@ -3182,7 +3191,8 @@ unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_or`
@@ -3198,7 +3208,8 @@ unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_xor`
@@ -3215,7 +3226,8 @@ unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the max value (signed comparison)
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_max`
@@ -3232,7 +3244,8 @@ unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the min value (signed comparison)
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_min`
@@ -3249,7 +3262,8 @@ unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the max value (unsigned comparison)
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_umax`
@@ -3266,7 +3280,8 @@ unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the min value (unsigned comparison)
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_umin`
index a4425fd234a4e22ad79ee3dfd4418464d80723ae..89adfccd90135233ef2ac66b533571bbbc3eeae5 100644 (file)
@@ -174,6 +174,7 @@ pub const fn new(
 /// Currently, `Context` only serves to provide access to a [`&Waker`](Waker)
 /// which can be used to wake the current task.
 #[stable(feature = "futures_api", since = "1.36.0")]
+#[cfg_attr(not(bootstrap), lang = "Context")]
 pub struct Context<'a> {
     waker: &'a Waker,
     // Ensure we future-proof against variance changes by forcing
index c4e105cba600d008c76b3f8042ec91a0ee566c0f..a2b9bb551e677c57672721373a2866f624a307e5 100644 (file)
@@ -15,7 +15,7 @@ macro_rules! test_literal {
         for input in inputs {
             assert_eq!(input.parse(), Ok(x64));
             assert_eq!(input.parse(), Ok(x32));
-            let neg_input = &format!("-{input}");
+            let neg_input = format!("-{input}");
             assert_eq!(neg_input.parse(), Ok(-x64));
             assert_eq!(neg_input.parse(), Ok(-x32));
         }
index fd35d96c3fef814bd7952fb8b13afbcd7f31354f..39559cdbb5ea9c275b9b3db5b1db08291ec90c64 100644 (file)
@@ -1488,7 +1488,7 @@ macro_rules! panic_cases {
                 // optional:
                 //
                 // one or more similar inputs for which data[input] succeeds,
-                // and the corresponding output as an array.  This helps validate
+                // and the corresponding output as an array. This helps validate
                 // "critical points" where an input range straddles the boundary
                 // between valid and invalid.
                 // (such as the input `len..len`, which is just barely valid)
index 012182e090b9f1b2ab3bef92a654a6bfd7ec0837..d576bd0ccee03b5d4ea32070dd410f94a1ac131c 100644 (file)
@@ -69,7 +69,7 @@ fn dot(x: &[f64], y: &[f64]) -> f64 {
 #[cfg(test)]
 #[test]
 fn test() {
-    assert_eq!(&format!("{:.9}", spectral_norm(100)), "1.274219991");
+    assert_eq!(format!("{:.9}", spectral_norm(100)), "1.274219991");
 }
 
 fn main() {
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 5c5ef0b1125a0d712a5ef787ce99ab5f0ec801f0..286ad68fd13e8fdf70efab2fb31cb122ec23286d 100644 (file)
@@ -1512,7 +1512,7 @@ pub fn is_dir(&self) -> bool {
     }
 
     /// Tests whether this file type represents a regular file.
-    /// The result is  mutually exclusive to the results of
+    /// The result is mutually exclusive to the results of
     /// [`is_dir`] and [`is_symlink`]; only zero or one of these
     /// tests may pass.
     ///
index eb582be012bd54d72940ab3c694d99c769e0b236..839fdc96632d1eea31a5e621d9ed66a24848d320 100644 (file)
@@ -12,6 +12,8 @@
 
 use rand::RngCore;
 
+#[cfg(target_os = "macos")]
+use crate::ffi::{c_char, c_int};
 #[cfg(unix)]
 use crate::os::unix::fs::symlink as symlink_dir;
 #[cfg(unix)]
@@ -24,8 +26,6 @@
 use crate::sys::fs::symlink_junction;
 #[cfg(target_os = "macos")]
 use crate::sys::weak::weak;
-#[cfg(target_os = "macos")]
-use libc::{c_char, c_int};
 
 macro_rules! check {
     ($e:expr) => {
index f4e688eb926cc7bff8962f1f79ecca455d7c27bc..4c1b7d57684ddcf01b890b8742bc4732588248e8 100644 (file)
@@ -288,8 +288,8 @@ fn seek(&mut self, _: SeekFrom) -> io::Result<u64> {
     let mut reader = BufReader::with_capacity(5, ErrAfterFirstSeekReader { first_seek: true });
     assert_eq!(reader.fill_buf().ok(), Some(&[0, 0, 0, 0, 0][..]));
 
-    // The following seek will require two underlying seeks.  The first will
-    // succeed but the second will fail.  This should still invalidate the
+    // The following seek will require two underlying seeks. The first will
+    // succeed but the second will fail. This should still invalidate the
     // buffer.
     assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err());
     assert_eq!(reader.buffer().len(), 0);
index 601c01c2128c816757c103d3a04f3c4c0dd8646c..3581484050dd1a4e506574b46d99ce609c5ed996 100644 (file)
@@ -374,10 +374,10 @@ macro_rules! static_assert {
 static_assert!(align_of::<SimpleMessage>() >= TAG_MASK + 1);
 static_assert!(align_of::<Custom>() >= TAG_MASK + 1);
 
-static_assert!(@usize_eq: (TAG_MASK & TAG_SIMPLE_MESSAGE), TAG_SIMPLE_MESSAGE);
-static_assert!(@usize_eq: (TAG_MASK & TAG_CUSTOM), TAG_CUSTOM);
-static_assert!(@usize_eq: (TAG_MASK & TAG_OS), TAG_OS);
-static_assert!(@usize_eq: (TAG_MASK & TAG_SIMPLE), TAG_SIMPLE);
+static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE_MESSAGE, TAG_SIMPLE_MESSAGE);
+static_assert!(@usize_eq: TAG_MASK & TAG_CUSTOM, TAG_CUSTOM);
+static_assert!(@usize_eq: TAG_MASK & TAG_OS, TAG_OS);
+static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE, TAG_SIMPLE);
 
 // This is obviously true (`TAG_CUSTOM` is `0b01`), but in `Repr::new_custom` we
 // offset a pointer by this value, and expect it to both be within the same
index 16c634e9afd50110519875b191aa035c3bc6e13e..9aea62a5b940c553cfb011ecb322f7ff7a5a9af0 100644 (file)
@@ -190,5 +190,5 @@ fn test_std_io_error_downcast() {
     let io_error = io_error.downcast::<E>().unwrap_err();
 
     assert_eq!(SIMPLE_MESSAGE.kind, io_error.kind());
-    assert_eq!(SIMPLE_MESSAGE.message, &*format!("{io_error}"));
+    assert_eq!(SIMPLE_MESSAGE.message, format!("{io_error}"));
 }
index a7e13f5b866b53058f0f995f5818e739c47c09de..762f7a7c9a1a0a5907b4c6f39a9bb29b8796f96b 100644 (file)
 #![feature(allocator_internals)]
 #![feature(allow_internal_unsafe)]
 #![feature(allow_internal_unstable)]
-#![feature(box_syntax)]
 #![feature(c_unwind)]
 #![feature(cfg_target_thread_local)]
 #![feature(concat_idents)]
 #![feature(const_ip)]
 #![feature(const_ipv4)]
 #![feature(const_ipv6)]
-#![feature(const_socketaddr)]
 #![feature(thread_local_internals)]
 //
 #![default_lib_allocator]
index 7c3430b2b217c5b838e22a63bf3511e846bc0f56..0eb59d45de727b6603bd32b1988b55fcb509e9ac 100644 (file)
@@ -125,8 +125,8 @@ fn ipv4_addr_to_string() {
     assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127");
 
     // Test padding
-    assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1         ");
-    assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), "         1.1.1.1");
+    assert_eq!(format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1         ");
+    assert_eq!(format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), "         1.1.1.1");
 }
 
 #[test]
@@ -148,8 +148,8 @@ fn ipv6_addr_to_string() {
         "1111:2222:3333:4444:5555:6666:7777:8888"
     );
     // padding
-    assert_eq!(&format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8     ");
-    assert_eq!(&format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "     1:2:3:4:5:6:7:8");
+    assert_eq!(format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8     ");
+    assert_eq!(format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "     1:2:3:4:5:6:7:8");
 
     // reduce a single run of zeros
     assert_eq!(
index 33b0dfa03e0ed3b029138814e459330962dbd1f5..1264bae809b264c21015bcbdc3f0d632dae93c46 100644 (file)
@@ -133,7 +133,7 @@ impl SocketAddr {
     /// ```
     #[stable(feature = "ip_addr", since = "1.7.0")]
     #[must_use]
-    #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn new(ip: IpAddr, port: u16) -> SocketAddr {
         match ip {
             IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
@@ -153,7 +153,7 @@ pub const fn new(ip: IpAddr, port: u16) -> SocketAddr {
     /// ```
     #[must_use]
     #[stable(feature = "ip_addr", since = "1.7.0")]
-    #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn ip(&self) -> IpAddr {
         match *self {
             SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
@@ -194,7 +194,7 @@ pub fn set_ip(&mut self, new_ip: IpAddr) {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn port(&self) -> u16 {
         match *self {
             SocketAddr::V4(ref a) => a.port(),
@@ -238,7 +238,7 @@ pub fn set_port(&mut self, new_port: u16) {
     /// ```
     #[must_use]
     #[stable(feature = "sockaddr_checker", since = "1.16.0")]
-    #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn is_ipv4(&self) -> bool {
         matches!(*self, SocketAddr::V4(_))
     }
@@ -260,7 +260,7 @@ pub const fn is_ipv4(&self) -> bool {
     /// ```
     #[must_use]
     #[stable(feature = "sockaddr_checker", since = "1.16.0")]
-    #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn is_ipv6(&self) -> bool {
         matches!(*self, SocketAddr::V6(_))
     }
@@ -280,7 +280,7 @@ impl SocketAddrV4 {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
-    #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
         SocketAddrV4 { ip, port }
     }
@@ -297,7 +297,7 @@ pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn ip(&self) -> &Ipv4Addr {
         &self.ip
     }
@@ -330,7 +330,7 @@ pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn port(&self) -> u16 {
         self.port
     }
@@ -371,7 +371,7 @@ impl SocketAddrV6 {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
-    #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 {
         SocketAddrV6 { ip, port, flowinfo, scope_id }
     }
@@ -388,7 +388,7 @@ pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> Socke
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn ip(&self) -> &Ipv6Addr {
         &self.ip
     }
@@ -421,7 +421,7 @@ pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn port(&self) -> u16 {
         self.port
     }
@@ -464,7 +464,7 @@ pub fn set_port(&mut self, new_port: u16) {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn flowinfo(&self) -> u32 {
         self.flowinfo
     }
@@ -504,7 +504,7 @@ pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn scope_id(&self) -> u32 {
         self.scope_id
     }
index 15211f81981ba1f6b5d1e24a06276c3a43eaa65e..dfc6dabbed1edeace9365cd0ed3bcdb89ea4e932 100644 (file)
@@ -64,11 +64,11 @@ fn ipv4_socket_addr_to_string() {
 
     // Test padding.
     assert_eq!(
-        &format!("{:16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)),
+        format!("{:16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)),
         "1.1.1.1:53      "
     );
     assert_eq!(
-        &format!("{:>16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)),
+        format!("{:>16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)),
         "      1.1.1.1:53"
     );
 }
@@ -111,11 +111,11 @@ fn ipv6_socket_addr_to_string() {
 
     // Test padding.
     assert_eq!(
-        &format!("{:22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)),
+        format!("{:22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)),
         "[1:2:3:4:5:6:7:8]:9   "
     );
     assert_eq!(
-        &format!("{:>22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)),
+        format!("{:>22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)),
         "   [1:2:3:4:5:6:7:8]:9"
     );
 }
index c6aa7c77dbc41d74ff1fb776de1d82c13be3a8bc..35de4860fe24925b215e84578bbba65c6a151fe5 100644 (file)
@@ -3,7 +3,7 @@
 //! This module is supported on Unix platforms and WASI, which both use a
 //! similar file descriptor system for referencing OS resources.
 
-#![stable(feature = "io_safety", since = "1.63.0")]
+#![stable(feature = "os_fd", since = "1.66.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 // `RawFd`, `AsRawFd`, etc.
@@ -19,7 +19,7 @@
 mod tests;
 
 // Export the types and traits for the public API.
-#[unstable(feature = "os_fd", issue = "98699")]
+#[stable(feature = "os_fd", since = "1.66.0")]
 pub use owned::*;
-#[unstable(feature = "os_fd", issue = "98699")]
+#[stable(feature = "os_fd", since = "1.66.0")]
 pub use raw::*;
index c16518577f7c466794127c9db77be3136e3d4c46..c41e093a7e5c6442f7022cd09d7f587f680af185 100644 (file)
@@ -100,7 +100,7 @@ pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
 
         // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
         // will never be supported, as this is a bare metal framework with
-        // no capabilities for multi-process execution.  While F_DUPFD is also
+        // no capabilities for multi-process execution. While F_DUPFD is also
         // not supported yet, it might be (currently it returns ENOSYS).
         #[cfg(target_os = "espidf")]
         let cmd = libc::F_DUPFD;
index df3fc8e6a3b660cfa61f85ccc38fff7501a95f9c..85065984fbbb19872e7c2935e683969b4e8feef2 100644 (file)
@@ -38,7 +38,7 @@ pub trait SocketAddrExt: Sealed {
     ///     Ok(())
     /// }
     /// ```
-    fn from_abstract_name<N>(name: &N) -> crate::io::Result<SocketAddr>
+    fn from_abstract_name<N>(name: N) -> crate::io::Result<SocketAddr>
     where
         N: AsRef<[u8]>;
 
index 5ec267c41e97ca77a5e3a920b30c918633e2fd77..b7046dd7c598c923f80b9bf470d957ebd64851f1 100644 (file)
@@ -1,4 +1,13 @@
 //! OS-specific networking functionality.
 
+// See cfg macros in `library/std/src/os/mod.rs` for why these platforms must
+// be special-cased during rustdoc generation.
+#[cfg(not(all(
+    doc,
+    any(
+        all(target_arch = "wasm32", not(target_os = "wasi")),
+        all(target_vendor = "fortanix", target_env = "sgx")
+    )
+)))]
 #[cfg(any(target_os = "linux", target_os = "android", doc))]
 pub(super) mod linux_ext;
index 81ac829d21bc81164006a02f55a81a32b0ad35c7..ece2b33bddf364e16c1421b68f5a37e362ee5793 100644 (file)
@@ -256,7 +256,7 @@ fn as_abstract_name(&self) -> Option<&[u8]> {
         if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None }
     }
 
-    fn from_abstract_name<N>(name: &N) -> crate::io::Result<Self>
+    fn from_abstract_name<N>(name: N) -> crate::io::Result<Self>
     where
         N: AsRef<[u8]>,
     {
index b30dd8eecd84c210d709d998cd15a95e77b5d2dc..b0db3112e22fd34470d06fa910b73ef4d118f4a7 100644 (file)
@@ -306,11 +306,11 @@ pub mod panic_count {
     // and after increase and decrease, but not necessarily during their execution.
     //
     // Additionally, the top bit of GLOBAL_PANIC_COUNT (GLOBAL_ALWAYS_ABORT_FLAG)
-    // records whether panic::always_abort() has been called.  This can only be
+    // records whether panic::always_abort() has been called. This can only be
     // set, never cleared.
     // panic::always_abort() is usually called to prevent memory allocations done by
     // the panic handling in the child created by `libc::fork`.
-    // Memory allocations performed in  a child created with `libc::fork` are undefined
+    // Memory allocations performed in a child created with `libc::fork` are undefined
     // behavior in most operating systems.
     // Accessing LOCAL_PANIC_COUNT in a child created by `libc::fork` would lead to a memory
     // allocation. Only GLOBAL_PANIC_COUNT can be accessed in this situation. This is
index a2dcee0e2bdb26ef252f04cd8feee8d217b27683..2f53cf83936910e1df1dc217f96a8884c6f53302 100644 (file)
@@ -607,7 +607,7 @@ pub struct Components<'a> {
 
     // true if path *physically* has a root separator; for most Windows
     // prefixes, it may have a "logical" root separator for the purposes of
-    // normalization, e.g.,  \\server\share == \\server\share\.
+    // normalization, e.g., \\server\share == \\server\share\.
     has_physical_root: bool,
 
     // The iterator is double-ended, and these two states keep track of what has
@@ -2531,6 +2531,8 @@ pub fn extension(&self) -> Option<&OsStr> {
 
     /// Creates an owned [`PathBuf`] with `path` adjoined to `self`.
     ///
+    /// If `path` is absolute, it replaces the current path.
+    ///
     /// See [`PathBuf::push`] for more details on what it means to adjoin a path.
     ///
     /// # Examples
@@ -2539,6 +2541,7 @@ pub fn extension(&self) -> Option<&OsStr> {
     /// use std::path::{Path, PathBuf};
     ///
     /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd"));
+    /// assert_eq!(Path::new("/etc").join("/bin/sh"), PathBuf::from("/bin/sh"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
index f942bdf18c1806ef55ab60733e2f2bb26a7062b5..cb52ae89b1911e06a59acc2e047dc565ed1c225b 100644 (file)
@@ -1,7 +1,7 @@
 //! On Emscripten Rust panics are wrapped in C++ exceptions, so we just forward
 //! to `__gxx_personality_v0` which is provided by Emscripten.
 
-use libc::c_int;
+use crate::ffi::c_int;
 use unwind as uw;
 
 // This is required by the compiler to exist (e.g., it's a lang item), but it's
index 5fc1b91a1c35780fda47ef22f7722a94b9966e22..41c0fe725a540bff6e99936f30b25ac29ebbb966 100644 (file)
@@ -37,7 +37,8 @@
 //! and the last personality routine transfers control to the catch block.
 
 use super::dwarf::eh::{self, EHAction, EHContext};
-use libc::{c_int, uintptr_t};
+use crate::ffi::c_int;
+use libc::uintptr_t;
 use unwind as uw;
 
 // Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
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 3edbe7280774d44d75ff56e5bb4100ff6b10d272..403a5e627f1e7fe6b2b6b71c0c2c13ede23a3f5a 100644 (file)
@@ -7,6 +7,7 @@
 #[cfg(any(
     target_arch = "x86",
     target_arch = "arm",
+    target_arch = "m68k",
     target_arch = "mips",
     target_arch = "powerpc",
     target_arch = "powerpc64",
index 8f65544a9e894de0a21f897911fea2d688cead06..2507f70695173396f81d8356b97ad1e24ec8f1f2 100644 (file)
@@ -27,10 +27,10 @@ pub unsafe fn new_with_coreid(
         p: Box<dyn FnOnce()>,
         core_id: isize,
     ) -> io::Result<Thread> {
-        let p = Box::into_raw(box p);
+        let p = Box::into_raw(Box::new(p));
         let tid = abi::spawn2(
             thread_start,
-            p as usize,
+            p.expose_addr(),
             abi::Priority::into(abi::NORMAL_PRIO),
             stack,
             core_id,
index 9b683fce157488df8d26ee08184e278578e5c17b..613266b9530a800d47560ebb3d5f018b17732387 100644 (file)
@@ -5,32 +5,23 @@
 // The this solution works like the implementation of macOS and
 // doesn't additional OS support
 
-use crate::cell::Cell;
-use crate::ptr;
+use crate::mem;
 
 #[thread_local]
-static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
-
-type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
+static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
 
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
-    if DTORS.get().is_null() {
-        let v: Box<List> = box Vec::new();
-        DTORS.set(Box::into_raw(v));
-    }
-
-    let list: &mut List = &mut *DTORS.get();
+    let list = &mut DTORS;
     list.push((t, dtor));
 }
 
 // every thread call this function to run through all possible destructors
 pub unsafe fn run_dtors() {
-    let mut ptr = DTORS.replace(ptr::null_mut());
-    while !ptr.is_null() {
-        let list = Box::from_raw(ptr);
-        for (ptr, dtor) in list.into_iter() {
+    let mut list = mem::take(&mut DTORS);
+    while !list.is_empty() {
+        for (ptr, dtor) in list {
             dtor(ptr);
         }
-        ptr = DTORS.replace(ptr::null_mut());
+        list = mem::take(&mut DTORS);
     }
 }
index 535703be33f06474724a37802df9b6d6fb4f7353..19350b83fab884d8cf3ebd0efdabb7b9de30d4a3 100644 (file)
@@ -294,7 +294,7 @@ fn drop(&mut self) {
                 // Terminate and delete the task
                 // Safety: `self.task` still represents a task we own (because
                 //         this method or `join_inner` is called only once for
-                //         each `Thread`). The task  indicated that it's safe to
+                //         each `Thread`). The task indicated that it's safe to
                 //         delete by entering the `FINISHED` state.
                 unsafe { terminate_and_delete_task(self.task) };
 
index 97356457057761014502ea74885732e75b42b248..bad14bb37f720e50707898944ca5e88212e358c9 100644 (file)
@@ -5,43 +5,35 @@
 
 use super::{abi, itron::task};
 use crate::cell::Cell;
-use crate::ptr;
+use crate::mem;
 
 #[thread_local]
-static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
+static REGISTERED: Cell<bool> = Cell::new(false);
 
-type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
+#[thread_local]
+static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
 
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
-    if DTORS.get().is_null() {
+    if !REGISTERED.get() {
         let tid = task::current_task_id_aborting();
-        let v: Box<List> = box Vec::new();
-        DTORS.set(Box::into_raw(v));
-
         // Register `tls_dtor` to make sure the TLS destructors are called
         // for tasks created by other means than `std::thread`
         unsafe { abi::SOLID_TLS_AddDestructor(tid as i32, tls_dtor) };
+        REGISTERED.set(true);
     }
 
-    let list: &mut List = unsafe { &mut *DTORS.get() };
+    let list = unsafe { &mut DTORS };
     list.push((t, dtor));
 }
 
 pub unsafe fn run_dtors() {
-    let ptr = DTORS.get();
-    if !ptr.is_null() {
-        // Swap the destructor list, call all registered destructors,
-        // and repeat this until the list becomes permanently empty.
-        while let Some(list) = Some(crate::mem::replace(unsafe { &mut *ptr }, Vec::new()))
-            .filter(|list| !list.is_empty())
-        {
-            for (ptr, dtor) in list.into_iter() {
-                unsafe { dtor(ptr) };
-            }
+    let mut list = mem::take(unsafe { &mut DTORS });
+    while !list.is_empty() {
+        for (ptr, dtor) in list {
+            unsafe { dtor(ptr) };
         }
 
-        // Drop the destructor list
-        unsafe { Box::from_raw(DTORS.replace(ptr::null_mut())) };
+        list = mem::take(unsafe { &mut DTORS });
     }
 }
 
index aea0c26ee8b60e8a2045208b6228a0dc5812d7b5..8e1f35d6cc92011cac5704c196d5384390e3de3c 100644 (file)
@@ -149,12 +149,13 @@ unsafe fn try_statx(
     ) -> Option<io::Result<FileAttr>> {
         use crate::sync::atomic::{AtomicU8, Ordering};
 
-        // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx`
-        // We store the availability in global to avoid unnecessary syscalls.
-        // 0: Unknown
-        // 1: Not available
-        // 2: Available
-        static STATX_STATE: AtomicU8 = AtomicU8::new(0);
+        // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx`.
+        // We check for it on first failure and remember availability to avoid having to
+        // do it again.
+        #[repr(u8)]
+        enum STATX_STATE{ Unknown = 0, Present, Unavailable }
+        static STATX_SAVED_STATE: AtomicU8 = AtomicU8::new(STATX_STATE::Unknown as u8);
+
         syscall! {
             fn statx(
                 fd: c_int,
@@ -165,31 +166,44 @@ fn statx(
             ) -> c_int
         }
 
-        match STATX_STATE.load(Ordering::Relaxed) {
-            0 => {
-                // It is a trick to call `statx` with null pointers to check if the syscall
-                // is available. According to the manual, it is expected to fail with EFAULT.
-                // We do this mainly for performance, since it is nearly hundreds times
-                // faster than a normal successful call.
-                let err = cvt(statx(0, ptr::null(), 0, libc::STATX_ALL, ptr::null_mut()))
-                    .err()
-                    .and_then(|e| e.raw_os_error());
-                // We don't check `err == Some(libc::ENOSYS)` because the syscall may be limited
-                // and returns `EPERM`. Listing all possible errors seems not a good idea.
-                // See: https://github.com/rust-lang/rust/issues/65662
-                if err != Some(libc::EFAULT) {
-                    STATX_STATE.store(1, Ordering::Relaxed);
-                    return None;
-                }
-                STATX_STATE.store(2, Ordering::Relaxed);
-            }
-            1 => return None,
-            _ => {}
+        if STATX_SAVED_STATE.load(Ordering::Relaxed) == STATX_STATE::Unavailable as u8 {
+            return None;
         }
 
         let mut buf: libc::statx = mem::zeroed();
         if let Err(err) = cvt(statx(fd, path, flags, mask, &mut buf)) {
-            return Some(Err(err));
+            if STATX_SAVED_STATE.load(Ordering::Relaxed) == STATX_STATE::Present as u8 {
+                return Some(Err(err));
+            }
+
+            // Availability not checked yet.
+            //
+            // First try the cheap way.
+            if err.raw_os_error() == Some(libc::ENOSYS) {
+                STATX_SAVED_STATE.store(STATX_STATE::Unavailable as u8, Ordering::Relaxed);
+                return None;
+            }
+
+            // Error other than `ENOSYS` is not a good enough indicator -- it is
+            // known that `EPERM` can be returned as a result of using seccomp to
+            // block the syscall.
+            // Availability is checked by performing a call which expects `EFAULT`
+            // if the syscall is usable.
+            // See: https://github.com/rust-lang/rust/issues/65662
+            // FIXME this can probably just do the call if `EPERM` was received, but
+            // previous iteration of the code checked it for all errors and for now
+            // this is retained.
+            // FIXME what about transient conditions like `ENOMEM`?
+            let err2 = cvt(statx(0, ptr::null(), 0, libc::STATX_ALL, ptr::null_mut()))
+                .err()
+                .and_then(|e| e.raw_os_error());
+            if err2 == Some(libc::EFAULT) {
+                STATX_SAVED_STATE.store(STATX_STATE::Present as u8, Ordering::Relaxed);
+                return Some(Err(err));
+            } else {
+                STATX_SAVED_STATE.store(STATX_STATE::Unavailable as u8, Ordering::Relaxed);
+                return None;
+            }
         }
 
         // We cannot fill `stat64` exhaustively because of private padding fields.
@@ -600,13 +614,13 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
             loop {
                 // As of POSIX.1-2017, readdir() is not required to be thread safe; only
                 // readdir_r() is. However, readdir_r() cannot correctly handle platforms
-                // with unlimited or variable NAME_MAX.  Many modern platforms guarantee
+                // with unlimited or variable NAME_MAX. Many modern platforms guarantee
                 // thread safety for readdir() as long an individual DIR* is not accessed
                 // concurrently, which is sufficient for Rust.
                 super::os::set_errno(0);
                 let entry_ptr = readdir64(self.inner.dirp.0);
                 if entry_ptr.is_null() {
-                    // We either encountered an error, or reached the end.  Either way,
+                    // We either encountered an error, or reached the end. Either way,
                     // the next call to next() should return None.
                     self.end_of_stream = true;
 
index 0f7107122b7e86ecbba33e56b46efcd52ef2fcbc..73b9bef7e2ac9b68b3b8480d27a2e288a7c4cd24 100644 (file)
@@ -587,7 +587,7 @@ fn copy_file_range(
                         // - copy_file_range file is immutable or syscall is blocked by seccomp¹ (EPERM)
                         // - copy_file_range cannot be used with pipes or device nodes (EINVAL)
                         // - the writer fd was opened with O_APPEND (EBADF²)
-                        // and no bytes were written successfully yet.  (All these errnos should
+                        // and no bytes were written successfully yet. (All these errnos should
                         // not be returned if something was already written, but they happen in
                         // the wild, see #91152.)
                         //
index 4c99d758c93a3156e1ccfafe6252443c4f4468b5..d4c7e58b34d2ef85c2d5864962928745d6eebd14 100644 (file)
@@ -262,7 +262,7 @@ pub fn signal(&self) -> Option<i32> {
     // available on Fuchsia.
     //
     // It does not appear that Fuchsia is Unix-like enough to implement ExitStatus (or indeed many
-    // other things from std::os::unix) properly.  This veneer is always going to be a bodge.  So
+    // other things from std::os::unix) properly. This veneer is always going to be a bodge. So
     // while I don't know if these implementations are actually correct, I think they will do for
     // now at least.
     pub fn core_dumped(&self) -> bool {
@@ -277,9 +277,9 @@ pub fn continued(&self) -> bool {
 
     pub fn into_raw(&self) -> c_int {
         // We don't know what someone who calls into_raw() will do with this value, but it should
-        // have the conventional Unix representation.  Despite the fact that this is not
+        // have the conventional Unix representation. Despite the fact that this is not
         // standardised in SuS or POSIX, all Unix systems encode the signal and exit status the
-        // same way.  (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every
+        // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every
         // Unix.)
         //
         // The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may
@@ -287,14 +287,14 @@ pub fn into_raw(&self) -> c_int {
         // different Unix variant.
         //
         // The other view would be to say that the caller on Fuchsia ought to know that `into_raw`
-        // will give a raw Fuchsia status (whatever that is - I don't know, personally).  That is
+        // will give a raw Fuchsia status (whatever that is - I don't know, personally). That is
         // not possible here because we must return a c_int because that's what Unix (including
         // SuS and POSIX) say a wait status is, but Fuchsia apparently uses a u64, so it won't
         // necessarily fit.
         //
         // It seems to me that the right answer would be to provide std::os::fuchsia with its
         // own ExitStatusExt, rather that trying to provide a not very convincing imitation of
-        // Unix.  Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia.  But
+        // Unix. Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia. But
         // fixing this up that is beyond the scope of my efforts now.
         let exit_status_as_if_unix: u8 = self.0.try_into().expect("Fuchsia process return code bigger than 8 bits, but std::os::unix::ExitStatusExt::into_raw() was called to try to convert the value into a traditional Unix-style wait status, which cannot represent values greater than 255.");
         let wait_status_as_if_unix = (exit_status_as_if_unix as c_int) << 8;
index 39d1c8b1d8ebc75d0da500c882e4683bd167ba40..3bc17b7754d85b7405c7eb33095cb8372e681f41 100644 (file)
@@ -666,11 +666,11 @@ fn exited(&self) -> bool {
     }
 
     pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
-        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0.  This is
+        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
         // true on all actual versions of Unix, is widely assumed, and is specified in SuS
-        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html .  If it is not
+        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not
         // true for a platform pretending to be Unix, the tests (our doctests, and also
-        // procsss_unix/tests.rs) will spot it.  `ExitStatusError::code` assumes this too.
+        // procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
         match NonZero_c_int::try_from(self.0) {
             /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
             /* was zero, couldn't convert */ Err(_) => Ok(()),
@@ -746,6 +746,8 @@ fn signal_string(signal: i32) -> &'static str {
         libc::SIGWINCH => " (SIGWINCH)",
         #[cfg(not(target_os = "haiku"))]
         libc::SIGIO => " (SIGIO)",
+        #[cfg(target_os = "haiku")]
+        libc::SIGPOLL => " (SIGPOLL)",
         libc::SIGSYS => " (SIGSYS)",
         // For information on Linux signals, run `man 7 signal`
         #[cfg(all(
index 4c87f633a260919fb958b204c0cdf6c1a2ff9aaf..e5e1f956bc351e43c16878ea2d37b6b65d876025 100644 (file)
@@ -19,17 +19,17 @@ fn exitstatus_display_tests() {
     t(0x00000, "exit status: 0");
     t(0x0ff00, "exit status: 255");
 
-    // On MacOS, 0x0137f is WIFCONTINUED, not WIFSTOPPED.  Probably *BSD is similar.
+    // On MacOS, 0x0137f is WIFCONTINUED, not WIFSTOPPED. Probably *BSD is similar.
     //   https://github.com/rust-lang/rust/pull/82749#issuecomment-790525956
     // The purpose of this test is to test our string formatting, not our understanding of the wait
-    // status magic numbers.  So restrict these to Linux.
+    // status magic numbers. So restrict these to Linux.
     if cfg!(target_os = "linux") {
         t(0x0137f, "stopped (not terminated) by signal: 19 (SIGSTOP)");
         t(0x0ffff, "continued (WIFCONTINUED)");
     }
 
     // Testing "unrecognised wait status" is hard because the wait.h macros typically
-    // assume that the value came from wait and isn't mad.  With the glibc I have here
+    // assume that the value came from wait and isn't mad. With the glibc I have here
     // this works:
     if cfg!(all(target_os = "linux", target_env = "gnu")) {
         t(0x000ff, "unrecognised wait status: 255 0xff");
index f549d37c301165fad9019ca014f5770398cdcf5c..569a4b149125d618bd8847691b7b4434d8ab0cb7 100644 (file)
@@ -195,11 +195,11 @@ fn exited(&self) -> bool {
     }
 
     pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
-        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0.  This is
+        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
         // true on all actual versions of Unix, is widely assumed, and is specified in SuS
-        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html .  If it is not
+        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not
         // true for a platform pretending to be Unix, the tests (our doctests, and also
-        // procsss_unix/tests.rs) will spot it.  `ExitStatusError::code` assumes this too.
+        // procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
         match NonZero_c_int::try_from(self.0) {
             Ok(failure) => Err(ExitStatusError(failure)),
             Err(_) => Ok(()),
index b251949bda207e1bf0fcfa99750e7311f4412dce..cc0e5929569729ef17de83334958ca55eddad79f 100644 (file)
@@ -49,7 +49,7 @@ unsafe impl Sync for Thread {}
 impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
     pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
-        let p = Box::into_raw(box p);
+        let p = Box::into_raw(Box::new(p));
         let mut native: libc::pthread_t = mem::zeroed();
         let mut attr: libc::pthread_attr_t = mem::zeroed();
         assert_eq!(libc::pthread_attr_init(&mut attr), 0);
@@ -73,7 +73,7 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
                 n => {
                     assert_eq!(n, libc::EINVAL);
                     // EINVAL means |stack_size| is either too small or not a
-                    // multiple of the system page size.  Because it's definitely
+                    // multiple of the system page size. Because it's definitely
                     // >= PTHREAD_STACK_MIN, it must be an alignment issue.
                     // Round up to the nearest page and try again.
                     let page_size = os::page_size();
@@ -755,10 +755,10 @@ pub unsafe fn init() -> Option<Guard> {
         if cfg!(all(target_os = "linux", not(target_env = "musl"))) {
             // Linux doesn't allocate the whole stack right away, and
             // the kernel has its own stack-guard mechanism to fault
-            // when growing too close to an existing mapping.  If we map
+            // when growing too close to an existing mapping. If we map
             // our own guard, then the kernel starts enforcing a rather
             // large gap above that, rendering much of the possible
-            // stack space useless.  See #43052.
+            // stack space useless. See #43052.
             //
             // Instead, we'll just note where we expect rlimit to start
             // faulting, so our handler can report "stack overflow", and
@@ -774,14 +774,14 @@ pub unsafe fn init() -> Option<Guard> {
             None
         } else if cfg!(target_os = "freebsd") {
             // FreeBSD's stack autogrows, and optionally includes a guard page
-            // at the bottom.  If we try to remap the bottom of the stack
-            // ourselves, FreeBSD's guard page moves upwards.  So we'll just use
+            // at the bottom. If we try to remap the bottom of the stack
+            // ourselves, FreeBSD's guard page moves upwards. So we'll just use
             // the builtin guard page.
             let stackptr = get_stack_start_aligned()?;
             let guardaddr = stackptr.addr();
             // Technically the number of guard pages is tunable and controlled
             // by the security.bsd.stack_guard_page sysctl, but there are
-            // few reasons to change it from the default.  The default value has
+            // few reasons to change it from the default. The default value has
             // been 1 ever since FreeBSD 11.1 and 10.4.
             const GUARD_PAGES: usize = 1;
             let guard = guardaddr..guardaddr + GUARD_PAGES * page_size;
@@ -877,9 +877,9 @@ pub unsafe fn current() -> Option<Guard> {
             } else if cfg!(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))
             {
                 // glibc used to include the guard area within the stack, as noted in the BUGS
-                // section of `man pthread_attr_getguardsize`.  This has been corrected starting
+                // section of `man pthread_attr_getguardsize`. This has been corrected starting
                 // with glibc 2.27, and in some distro backports, so the guard is now placed at the
-                // end (below) the stack.  There's no easy way for us to know which we have at
+                // end (below) the stack. There's no easy way for us to know which we have at
                 // runtime, so we'll just match any fault in the range right above or below the
                 // stack base to call that fault a stack overflow.
                 Some(stackaddr - guardsize..stackaddr + guardsize)
index d7fd2130f7ccec5f84ff93187651e12d3550afc0..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;
@@ -57,44 +51,40 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
 #[cfg(target_os = "macos")]
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
     use crate::cell::Cell;
+    use crate::mem;
     use crate::ptr;
 
     #[thread_local]
     static REGISTERED: Cell<bool> = Cell::new(false);
+
+    #[thread_local]
+    static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
+
     if !REGISTERED.get() {
         _tlv_atexit(run_dtors, ptr::null_mut());
         REGISTERED.set(true);
     }
 
-    type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
-
-    #[thread_local]
-    static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
-    if DTORS.get().is_null() {
-        let v: Box<List> = box Vec::new();
-        DTORS.set(Box::into_raw(v));
-    }
-
     extern "C" {
         fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8);
     }
 
-    let list: &mut List = &mut *DTORS.get();
+    let list = &mut DTORS;
     list.push((t, dtor));
 
     unsafe extern "C" fn run_dtors(_: *mut u8) {
-        let mut ptr = DTORS.replace(ptr::null_mut());
-        while !ptr.is_null() {
-            let list = Box::from_raw(ptr);
-            for (ptr, dtor) in list.into_iter() {
+        let mut list = mem::take(&mut DTORS);
+        while !list.is_empty() {
+            for (ptr, dtor) in list {
                 dtor(ptr);
             }
-            ptr = DTORS.replace(ptr::null_mut());
+            list = mem::take(&mut DTORS);
         }
     }
 }
 
-#[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 352337ba322371d77b89aedc5d1a7cc756351f0d..d7adeb266ed93f30918a8fab50137fec6852be98 100644 (file)
@@ -157,7 +157,7 @@ fn next(&mut self) -> Option<PathBuf> {
         // Double quotes are used as a way of introducing literal semicolons
         // (since c:\some;dir is a valid Windows path). Double quotes are not
         // themselves permitted in path names, so there is no way to escape a
-        // double quote.  Quoted regions can appear in arbitrary locations, so
+        // double quote. Quoted regions can appear in arbitrary locations, so
         //
         //   c:\foo;c:\som"e;di"r;c:\bar
         //
index c5c9e97e646fb94fa6960c1da38ba09f1265f04b..ed58c47e0907bb5aab534b92f2e6a6d4e6ca4733 100644 (file)
@@ -22,11 +22,11 @@ pub struct Thread {
 impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
     pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
-        let p = Box::into_raw(box p);
+        let p = Box::into_raw(Box::new(p));
 
         // FIXME On UNIX, we guard against stack sizes that are too small but
         // that's because pthreads enforces that stacks are at least
-        // PTHREAD_STACK_MIN bytes big.  Windows has no such lower limit, it's
+        // PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's
         // just that below a certain threshold you can't do anything useful.
         // That threshold is application and architecture-specific, however.
         let ret = c::CreateThread(
index 5d43676adbb11f0428d99c796fe58eaa3b3b2c45..eb9167cd8552bb047fd7ef1a4707fd43b15a6be4 100644 (file)
@@ -221,7 +221,7 @@ fn ptr(&self) -> c::LPVOID {
 
 fn keyed_event_handle() -> c::HANDLE {
     const INVALID: c::HANDLE = ptr::invalid_mut(!0);
-    static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID);
+    static HANDLE: AtomicPtr<crate::ffi::c_void> = AtomicPtr::new(INVALID);
     match HANDLE.load(Relaxed) {
         INVALID => {
             let mut handle = c::INVALID_HANDLE_VALUE;
index fad4a63331b5976b11c57dfddf04a1aaea890e3d..2c38dfecf9734d75048cf2c3f2d92cb261ab8e75 100644 (file)
@@ -14,7 +14,7 @@
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::Duration;
 
-use libc::{c_int, c_void};
+use crate::ffi::{c_int, c_void};
 
 cfg_if::cfg_if! {
     if #[cfg(any(
@@ -47,7 +47,7 @@
         target_os = "dragonfly", target_os = "freebsd",
         target_os = "openbsd", target_os = "netbsd",
         target_os = "solaris", target_os = "illumos"))] {
-        use libc::c_uchar;
+        use crate::ffi::c_uchar;
         type IpV4MultiCastType = c_uchar;
     } else {
         type IpV4MultiCastType = c_int;
@@ -127,8 +127,8 @@ fn to_ipv6mr_interface(value: u32) -> c_int {
 }
 
 #[cfg(not(target_os = "android"))]
-fn to_ipv6mr_interface(value: u32) -> libc::c_uint {
-    value as libc::c_uint
+fn to_ipv6mr_interface(value: u32) -> crate::ffi::c_uint {
+    value as crate::ffi::c_uint
 }
 
 ////////////////////////////////////////////////////////////////////////////////
index 1d13a7171b0355f5734dbbdc7120e6fbf58d7781..844946eda031f792603f0e363f597a4006047948 100644 (file)
@@ -30,7 +30,7 @@ pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut
     static DTORS: StaticKey = StaticKey::new(Some(run_dtors));
     type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
     if DTORS.get().is_null() {
-        let v: Box<List> = box Vec::new();
+        let v: Box<List> = Box::new(Vec::new());
         DTORS.set(Box::into_raw(v) as *mut u8);
     }
     let list: &mut List = &mut *(DTORS.get() as *mut List);
index b30bb7b77efb25bdc1e7e43358eaa3c702a8779b..cf7c2e05a2e9df94c60d536b97ba27e5fa48d7f9 100644 (file)
@@ -1110,8 +1110,7 @@ unsafe fn try_initialize(&'static self, init: impl FnOnce() -> T) -> Option<&'st
             let ptr = if ptr.is_null() {
                 // If the lookup returned null, we haven't initialized our own
                 // local copy, so do that now.
-                let ptr: Box<Value<T>> = box Value { inner: LazyKeyInner::new(), key: self };
-                let ptr = Box::into_raw(ptr);
+                let ptr = Box::into_raw(Box::new(Value { inner: LazyKeyInner::new(), key: self }));
                 // SAFETY: At this point we are sure there is no value inside
                 // ptr so setting it will not affect anyone else.
                 unsafe {
index ecd06ebf743ab49969617210f0b326e6b45aaf5a..acf9c29083f62ce26518f3be9fbf3b22bfa67e91 100644 (file)
@@ -1,6 +1,6 @@
 //! Temporal quantification.
 //!
-//! # Examples:
+//! # Examples
 //!
 //! There are multiple ways to create a new [`Duration`]:
 //!
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 24cbe035f2fa7e3e9082d38a6c44355dd47711da..1ee68c8540bcc39518f81c7609c08fb036314bd8 100644 (file)
@@ -53,6 +53,7 @@ pub struct ConsoleTestState {
     pub metrics: MetricMap,
     pub failures: Vec<(TestDesc, Vec<u8>)>,
     pub not_failures: Vec<(TestDesc, Vec<u8>)>,
+    pub ignores: Vec<(TestDesc, Vec<u8>)>,
     pub time_failures: Vec<(TestDesc, Vec<u8>)>,
     pub options: Options,
 }
@@ -76,6 +77,7 @@ pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> {
             metrics: MetricMap::new(),
             failures: Vec::new(),
             not_failures: Vec::new(),
+            ignores: Vec::new(),
             time_failures: Vec::new(),
             options: opts.options,
         })
@@ -194,7 +196,10 @@ fn handle_test_result(st: &mut ConsoleTestState, completed_test: CompletedTest)
             st.passed += 1;
             st.not_failures.push((test, stdout));
         }
-        TestResult::TrIgnored => st.ignored += 1,
+        TestResult::TrIgnored => {
+            st.ignored += 1;
+            st.ignores.push((test, stdout));
+        }
         TestResult::TrBench(bs) => {
             st.metrics.insert_metric(
                 test.name.as_slice(),
index 0837ab16905130c18cd6c5086af909075c3d8feb..a431acfbc27538944219c626f48e10a0e7b0ec72 100644 (file)
@@ -254,6 +254,15 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
 
         self.write_plain("\n\n")?;
 
+        // Custom handling of cases where there is only 1 test to execute and that test was ignored.
+        // We want to show more detailed information(why was the test ignored) for investigation purposes.
+        if self.total_test_count == 1 && state.ignores.len() == 1 {
+            let test_desc = &state.ignores[0].0;
+            if let Some(im) = test_desc.ignore_message {
+                self.write_plain(format!("test: {}, ignore_message: {}\n\n", test_desc.name, im))?;
+            }
+        }
+
         Ok(success)
     }
 }
index 30dc4ff855315d2c0f0bca55669d580e50d7f92e..69fb529d7f563b56e310bb85cf6b7a1f8282b6f6 100644 (file)
@@ -116,7 +116,7 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt
     } else {
         if !opts.nocapture {
             // If we encounter a non-unwinding panic, flush any captured output from the current test,
-            // and stop  capturing output to ensure that the non-unwinding panic message is visible.
+            // and stop capturing output to ensure that the non-unwinding panic message is visible.
             // We also acquire the locks for both output streams to prevent output from other threads
             // from interleaving with the panic message or appearing after it.
             let builtin_panic_hook = panic::take_hook();
index 87b91f34498a37085fd81b98fbbe8e60f798e54f..3e8ccc91ab0517fd8ef676174a3e1d56c5ef9d59 100644 (file)
@@ -30,7 +30,7 @@ pub(crate) fn get_dbpath_for_term(term: &str) -> Option<PathBuf> {
         }
     } else {
         // Found nothing in TERMINFO_DIRS, use the default paths:
-        // According to  /etc/terminfo/README, after looking at
+        // According to /etc/terminfo/README, after looking at
         // ~/.terminfo, ncurses will search /etc/terminfo, then
         // /lib/terminfo, and eventually /usr/share/terminfo.
         // On Haiku the database can be found at /boot/system/data/terminfo
index 3a0260f86cf5d081f08a4b6122a0f40c3ed77b38..44776fb0a316df90b0198076335e2b323f976d2b 100644 (file)
@@ -790,6 +790,7 @@ fn should_sort_failures_before_printing_them() {
         failures: vec![(test_b, Vec::new()), (test_a, Vec::new())],
         options: Options::new(),
         not_failures: Vec::new(),
+        ignores: Vec::new(),
         time_failures: Vec::new(),
     };
 
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 9cf43fc7a2193f1b67c5cd51e2927e98dff7b941..abdd12127d36659fdcd30e333deedb3a465a36e6 100644 (file)
@@ -712,7 +712,7 @@ class RustBuild(object):
 
     def build_bootstrap(self, color):
         """Build bootstrap"""
-        print("Building rustbuild")
+        print("Building bootstrap")
         build_dir = os.path.join(self.build_dir, "bootstrap")
         if self.clean and os.path.exists(build_dir):
             shutil.rmtree(build_dir)
index 7128d542acfe9d0609c165c3c7b074bd904c2d0c..65c882fb801e5b736e8958cc7b5fcf381a67a0b5 100644 (file)
@@ -47,6 +47,8 @@ fn cc2ar(cc: &Path, target: TargetSelection) -> Option<PathBuf> {
         Some(PathBuf::from("ar"))
     } else if target.contains("vxworks") {
         Some(PathBuf::from("wr-ar"))
+    } else if target.contains("android") {
+        Some(cc.parent().unwrap().join(PathBuf::from("llvm-ar")))
     } else {
         let parent = cc.parent().unwrap();
         let file = cc.file_name().unwrap().to_str().unwrap();
@@ -219,12 +221,22 @@ fn set_compiler(
 }
 
 pub(crate) fn ndk_compiler(compiler: Language, triple: &str, ndk: &Path) -> PathBuf {
-    let triple_translated = triple
-        .replace("armv7neon", "arm")
-        .replace("armv7", "arm")
-        .replace("thumbv7neon", "arm")
-        .replace("thumbv7", "arm");
-    let compiler = format!("{}-{}", triple_translated, compiler.clang());
+    let mut triple_iter = triple.split("-");
+    let triple_translated = if let Some(arch) = triple_iter.next() {
+        let arch_new = match arch {
+            "arm" | "armv7" | "armv7neon" | "thumbv7" | "thumbv7neon" => "armv7a",
+            other => other,
+        };
+        std::iter::once(arch_new).chain(triple_iter).collect::<Vec<&str>>().join("-")
+    } else {
+        triple.to_string()
+    };
+
+    // API 19 is the earliest API level supported by NDK r25b but AArch64 and x86_64 support
+    // begins at API level 21.
+    let api_level =
+        if triple.contains("aarch64") || triple.contains("x86_64") { "21" } else { "19" };
+    let compiler = format!("{}{}-{}", triple_translated, api_level, compiler.clang());
     ndk.join("bin").join(compiler)
 }
 
index b41d60d51a8b5972f75ea63e518d68e461f7df0e..fdd659c60ca7f51181fc0280a1b5309a0207ad03 100644 (file)
@@ -965,6 +965,9 @@ fn parse_inner<'a>(args: &[String], get_toml: impl 'a + Fn(&Path) -> TomlConfig)
         config.changelog_seen = toml.changelog_seen;
 
         let build = toml.build.unwrap_or_default();
+        if let Some(file_build) = build.build {
+            config.build = TargetSelection::from_user(&file_build);
+        };
 
         set(&mut config.out, flags.build_dir.or_else(|| build.build_dir.map(PathBuf::from)));
         // NOTE: Bootstrap spawns various commands with different working directories.
index c30c9131745c81e2f41cf8277852685ac1df579c..681ecbfeb5b8fca058a53948d10bee17ab8d8bd7 100644 (file)
@@ -19,6 +19,13 @@ fn download_ci_llvm() {
     assert_eq!(parse_llvm(""), if_available);
     assert_eq!(parse_llvm("rust.channel = \"dev\""), if_available);
     assert!(!parse_llvm("rust.channel = \"stable\""));
+    assert!(parse_llvm("build.build = \"x86_64-unknown-linux-gnu\""));
+    assert!(parse_llvm(
+        "llvm.assertions = true \r\n build.build = \"x86_64-unknown-linux-gnu\" \r\n llvm.download-ci-llvm = \"if-available\""
+    ));
+    assert!(!parse_llvm(
+        "llvm.assertions = true \r\n build.build = \"aarch64-apple-darwin\" \r\n llvm.download-ci-llvm = \"if-available\""
+    ));
 }
 
 // FIXME: add test for detecting `src` and `out`
index 68215790bed177e3fdd3b4376da622b612bc689a..02e35d2436e2f48b4e4b3a40f1ae758e49ea665a 100644 (file)
@@ -392,19 +392,29 @@ fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
             t!(fs::create_dir_all(image.join("bin")));
             builder.cp_r(&src.join("bin"), &image.join("bin"));
 
-            builder.install(&builder.rustdoc(compiler), &image.join("bin"), 0o755);
+            if builder
+                .config
+                .tools
+                .as_ref()
+                .map_or(true, |tools| tools.iter().any(|tool| tool == "rustdoc"))
+            {
+                let rustdoc = builder.rustdoc(compiler);
+                builder.install(&rustdoc, &image.join("bin"), 0o755);
+            }
 
-            let ra_proc_macro_srv = builder
-                .ensure(tool::RustAnalyzerProcMacroSrv {
+            if let Some(ra_proc_macro_srv) = builder.ensure_if_default(
+                tool::RustAnalyzerProcMacroSrv {
                     compiler: builder.compiler_for(
                         compiler.stage,
                         builder.config.build,
                         compiler.host,
                     ),
                     target: compiler.host,
-                })
-                .expect("rust-analyzer-proc-macro-server always builds");
-            builder.install(&ra_proc_macro_srv, &image.join("libexec"), 0o755);
+                },
+                builder.kind,
+            ) {
+                builder.install(&ra_proc_macro_srv, &image.join("libexec"), 0o755);
+            }
 
             let libdir_relative = builder.libdir_relative(compiler);
 
@@ -952,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);
 
@@ -1130,12 +1140,6 @@ fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
         let compiler = self.compiler;
         let target = self.target;
 
-        if target.contains("riscv64") {
-            // riscv64 currently has an LLVM bug that makes rust-analyzer unable
-            // to build. See #74813 for details.
-            return None;
-        }
-
         let rust_analyzer = builder
             .ensure(tool::RustAnalyzer { compiler, target })
             .expect("rust-analyzer always builds");
index d44b96cfb991ece07a53944f225a0624737b2921..3b9dba4109d3e6f1d2b8fe6c4aa047b204da4b5f 100644 (file)
@@ -1431,6 +1431,14 @@ fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, DependencyType)> {
             return Vec::new();
         }
 
+        if !stamp.exists() {
+            eprintln!(
+                "Error: Unable to find the stamp file {}, did you try to keep a nonexistent build stage?",
+                stamp.display()
+            );
+            crate::detail_exit(1);
+        }
+
         let mut paths = Vec::new();
         let contents = t!(fs::read(stamp), &stamp);
         // This is the method we use for extracting paths from the stamp file passed to us. See
index e0d1504c9c780a85ae83d32f81ae8fc0c7086375..3acc2d4b5c4b1093a2ab204c1e3b2861d3e864bf 100644 (file)
@@ -180,43 +180,40 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool {
     // https://doc.rust-lang.org/rustc/platform-support.html#tier-1
     let supported_platforms = [
         // tier 1
-        "aarch64-unknown-linux-gnu",
-        "i686-pc-windows-gnu",
-        "i686-pc-windows-msvc",
-        "i686-unknown-linux-gnu",
-        "x86_64-unknown-linux-gnu",
-        "x86_64-apple-darwin",
-        "x86_64-pc-windows-gnu",
-        "x86_64-pc-windows-msvc",
+        ("aarch64-unknown-linux-gnu", false),
+        ("i686-pc-windows-gnu", false),
+        ("i686-pc-windows-msvc", false),
+        ("i686-unknown-linux-gnu", false),
+        ("x86_64-unknown-linux-gnu", true),
+        ("x86_64-apple-darwin", true),
+        ("x86_64-pc-windows-gnu", true),
+        ("x86_64-pc-windows-msvc", true),
         // tier 2 with host tools
-        "aarch64-apple-darwin",
-        "aarch64-pc-windows-msvc",
-        "aarch64-unknown-linux-musl",
-        "arm-unknown-linux-gnueabi",
-        "arm-unknown-linux-gnueabihf",
-        "armv7-unknown-linux-gnueabihf",
-        "mips-unknown-linux-gnu",
-        "mips64-unknown-linux-gnuabi64",
-        "mips64el-unknown-linux-gnuabi64",
-        "mipsel-unknown-linux-gnu",
-        "powerpc-unknown-linux-gnu",
-        "powerpc64-unknown-linux-gnu",
-        "powerpc64le-unknown-linux-gnu",
-        "riscv64gc-unknown-linux-gnu",
-        "s390x-unknown-linux-gnu",
-        "x86_64-unknown-freebsd",
-        "x86_64-unknown-illumos",
-        "x86_64-unknown-linux-musl",
-        "x86_64-unknown-netbsd",
+        ("aarch64-apple-darwin", false),
+        ("aarch64-pc-windows-msvc", false),
+        ("aarch64-unknown-linux-musl", false),
+        ("arm-unknown-linux-gnueabi", false),
+        ("arm-unknown-linux-gnueabihf", false),
+        ("armv7-unknown-linux-gnueabihf", false),
+        ("mips-unknown-linux-gnu", false),
+        ("mips64-unknown-linux-gnuabi64", false),
+        ("mips64el-unknown-linux-gnuabi64", false),
+        ("mipsel-unknown-linux-gnu", false),
+        ("powerpc-unknown-linux-gnu", false),
+        ("powerpc64-unknown-linux-gnu", false),
+        ("powerpc64le-unknown-linux-gnu", false),
+        ("riscv64gc-unknown-linux-gnu", false),
+        ("s390x-unknown-linux-gnu", false),
+        ("x86_64-unknown-freebsd", false),
+        ("x86_64-unknown-illumos", false),
+        ("x86_64-unknown-linux-musl", false),
+        ("x86_64-unknown-netbsd", false),
     ];
-    if !supported_platforms.contains(&&*config.build.triple) {
-        return false;
-    }
 
-    let triple = &*config.build.triple;
-    if (triple == "aarch64-unknown-linux-gnu" || triple.contains("i686")) && asserts {
-        // No alt builder for aarch64-unknown-linux-gnu today.
-        return false;
+    if !supported_platforms.contains(&(&*config.build.triple, asserts)) {
+        if asserts == true || !supported_platforms.contains(&(&*config.build.triple, true)) {
+            return false;
+        }
     }
 
     if CiEnv::is_ci() {
@@ -1105,6 +1102,12 @@ fn supported_sanitizers(
         "x86_64-unknown-linux-musl" => {
             common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
         }
+        "s390x-unknown-linux-gnu" => {
+            common_libs("linux", "s390x", &["asan", "lsan", "msan", "tsan"])
+        }
+        "s390x-unknown-linux-musl" => {
+            common_libs("linux", "s390x", &["asan", "lsan", "msan", "tsan"])
+        }
         _ => Vec::new(),
     }
 }
index 9a2100c2fb785e6b6b264ecdf6cf76778bcaf562..ca5f500f93bc41deea9db9be5a6698f1154ab021 100644 (file)
@@ -765,9 +765,15 @@ impl Step for RustAnalyzerProcMacroSrv {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        let builder = run.builder;
         // Allow building `rust-analyzer-proc-macro-srv` both as part of the `rust-analyzer` and as a stand-alone tool.
         run.path("src/tools/rust-analyzer")
             .path("src/tools/rust-analyzer/crates/proc-macro-srv-cli")
+            .default_condition(builder.config.tools.as_ref().map_or(true, |tools| {
+                tools
+                    .iter()
+                    .any(|tool| tool == "rust-analyzer" || tool == "rust-analyzer-proc-macro-srv")
+            }))
     }
 
     fn make_run(run: RunConfig<'_>) {
index 7a875c960e13312d77d11983c0f4bab304b4c554..b6b4fdc67a94905a2d6e28f2b56d01c44ceeb6dc 100644 (file)
@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ubuntu:22.10
 
 ARG DEBIAN_FRONTEND=noninteractive
 COPY scripts/android-base-apt-get.sh /scripts/
@@ -6,7 +6,7 @@ RUN sh /scripts/android-base-apt-get.sh
 
 COPY scripts/android-ndk.sh /scripts/
 RUN . /scripts/android-ndk.sh && \
-    download_and_make_toolchain android-ndk-r15c-linux-x86_64.zip arm 14
+    download_ndk android-ndk-r25b-linux.zip
 
 RUN dpkg --add-architecture i386 && \
     apt-get update && \
@@ -30,7 +30,7 @@ ENV PATH=$PATH:/android/sdk/platform-tools
 
 ENV TARGETS=arm-linux-androideabi
 
-ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14
+ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/
 
 ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS
 
index 2328db4ab8b1d126dd774a67a744afb990bde1e0..9c6f648896b5127559decfa7d37c229650ca7173 100644 (file)
@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ubuntu:22.10
 
 COPY scripts/android-base-apt-get.sh /scripts/
 RUN sh /scripts/android-base-apt-get.sh
@@ -6,14 +6,7 @@ RUN sh /scripts/android-base-apt-get.sh
 # ndk
 COPY scripts/android-ndk.sh /scripts/
 RUN . /scripts/android-ndk.sh && \
-    download_ndk android-ndk-r15c-linux-x86_64.zip && \
-    make_standalone_toolchain arm 14 && \
-    make_standalone_toolchain x86 14 && \
-    make_standalone_toolchain arm 21 && \
-    make_standalone_toolchain x86 21 && \
-    make_standalone_toolchain arm64 21 && \
-    make_standalone_toolchain x86_64 21 && \
-    remove_ndk
+    download_ndk android-ndk-r25b-linux.zip
 
 # env
 ENV TARGETS=arm-linux-androideabi
@@ -26,12 +19,12 @@ ENV TARGETS=$TARGETS,x86_64-linux-android
 ENV RUST_CONFIGURE_ARGS \
       --enable-extended \
       --enable-profiler \
-      --arm-linux-androideabi-ndk=/android/ndk/arm-14 \
-      --armv7-linux-androideabi-ndk=/android/ndk/arm-14 \
-      --thumbv7neon-linux-androideabi-ndk=/android/ndk/arm-14 \
-      --i686-linux-android-ndk=/android/ndk/x86-14 \
-      --aarch64-linux-android-ndk=/android/ndk/arm64-21 \
-      --x86_64-linux-android-ndk=/android/ndk/x86_64-21 \
+      --arm-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
+      --armv7-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
+      --thumbv7neon-linux-androideabi-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
+      --i686-linux-android-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
+      --aarch64-linux-android-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
+      --x86_64-linux-android-ndk=/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/ \
       --disable-docs
 
 ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
index 43a449b3a1926baa307e1908dbdd1a6a1c2260c8..adb98d7ebb54541e83fbd61d1c877a169119a1cd 100644 (file)
@@ -28,5 +28,5 @@ ENV \
 
 ENV HOSTS=s390x-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --enable-profiler --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --enable-sanitizers --enable-profiler --disable-docs
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
index 67cee0148b24ec4cbb9a3e47f1aa379879106319..5fbce36c39d2844ba3b6be365f97822913f1e2a0 100755 (executable)
@@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04/bin"
 git clone https://github.com/WebAssembly/wasi-libc
 
 cd wasi-libc
-git reset --hard 8b7148f69ae241a2749b3defe4606da8143b72e0
+git reset --hard 4362b1885fd369e042a7c0ecd8df3b6cd47fb4e8
 make -j$(nproc) \
     CC="$bin/clang" \
     NM="$bin/llvm-nm" \
index dc0e591cad6f6f9aec51a1ab2eec129f01e9988b..889a586b351d6f30f700d433461b5951fd80f92a 100644 (file)
@@ -1,8 +1,6 @@
-FROM ubuntu:18.04
-# FIXME: when bumping the version, remove the Python 3.6-specific changes in
-# the reuse-requirements.in file, regenerate reuse-requirements.txt and remove
-# this comment.
+FROM ubuntu:22.04
 
+ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++ \
   make \
index d5bc76eeb23daee6779672485caf84fcf53ac877..4cc5d9f8a0dafd08bb59e6b92feb618fba17ad02 100644 (file)
@@ -1,8 +1,6 @@
-FROM ubuntu:18.04
-# FIXME: when bumping the version, remove the Python 3.6-specific changes in
-# the reuse-requirements.in file, regenerate reuse-requirements.txt and remove
-# this comment.
+FROM ubuntu:22.04
 
+ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++ \
   make \
index 4964f40aa39adaf30ae30d846d981655df2635e5..c7b3376e2f1fb97d06a6153719677f8db7365467 100644 (file)
 #
 
 reuse
-
-# Some packages dropped support for Python 3.6, which is the version used in
-# this builder (due to Ubuntu 18.04). This should be removed once we bump the
-# Ubuntu version of the builder.
-jinja2 < 3.1
-markupsafe < 2.1
-requests < 2.28
-setuptools < 59.7
index 10a5f73879082ce111af651a779a5c0c1bf2c2af..b0f598f77ea6f38bfebc810621affead94a7d82c 100644 (file)
@@ -1,6 +1,6 @@
 #
-# This file is autogenerated by pip-compile with python 3.10
-# To update, run:
+# This file is autogenerated by pip-compile with Python 3.10
+# by the following command:
 #
 #    pip-compile --allow-unsafe --generate-hashes reuse-requirements.in
 #
@@ -8,138 +8,77 @@ binaryornot==0.4.4 \
     --hash=sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061 \
     --hash=sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4
     # via reuse
-boolean-py==3.8 \
-    --hash=sha256:cc24e20f985d60cd4a3a5a1c0956dd12611159d32a75081dabd0c9ab981acaa4 \
-    --hash=sha256:d75da0fd0354425fa64f6bbc6cec6ae1485d0eec3447b73187ff8cbf9b572e26
+boolean-py==4.0 \
+    --hash=sha256:17b9a181630e43dde1851d42bef546d616d5d9b4480357514597e78b203d06e4 \
+    --hash=sha256:2876f2051d7d6394a531d82dc6eb407faa0b01a0a0b3083817ccd7323b8d96bd
     # via
     #   license-expression
     #   reuse
-certifi==2022.6.15 \
-    --hash=sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d \
-    --hash=sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412
-    # via requests
-chardet==5.0.0 \
-    --hash=sha256:0368df2bfd78b5fc20572bb4e9bb7fb53e2c094f60ae9993339e8671d0afb8aa \
-    --hash=sha256:d3e64f022d254183001eccc5db4040520c0f23b1a3f33d6413e099eb7f126557
+chardet==5.1.0 \
+    --hash=sha256:0d62712b956bc154f85fb0a266e2a3c5913c2967e00348701b32411d6def31e5 \
+    --hash=sha256:362777fb014af596ad31334fde1e8c327dfdb076e1960d1694662d46a6917ab9
     # via
     #   binaryornot
     #   python-debian
-charset-normalizer==2.0.12 \
-    --hash=sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597 \
-    --hash=sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df
-    # via requests
-idna==3.3 \
-    --hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \
-    --hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d
-    # via requests
-jinja2==3.0.3 \
-    --hash=sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8 \
-    --hash=sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7
-    # via
-    #   -r reuse-requirements.in
-    #   reuse
-license-expression==21.6.14 \
-    --hash=sha256:324246eed8e138b4139fefdc0e9dc4161d5075e3929e56983966d37298dca30e \
-    --hash=sha256:9de87a427c9a449eee7913472fb9ed03b63036295547369fdbf95f76a8b924b2
-    # via
-    #   -r reuse-requirements.in
-    #   reuse
-markupsafe==2.0.1 \
-    --hash=sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298 \
-    --hash=sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64 \
-    --hash=sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b \
-    --hash=sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194 \
-    --hash=sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567 \
-    --hash=sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff \
-    --hash=sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724 \
-    --hash=sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74 \
-    --hash=sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646 \
-    --hash=sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35 \
-    --hash=sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6 \
-    --hash=sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a \
-    --hash=sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6 \
-    --hash=sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad \
-    --hash=sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26 \
-    --hash=sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38 \
-    --hash=sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac \
-    --hash=sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7 \
-    --hash=sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6 \
-    --hash=sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047 \
-    --hash=sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75 \
-    --hash=sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f \
-    --hash=sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b \
-    --hash=sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135 \
-    --hash=sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8 \
-    --hash=sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a \
-    --hash=sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a \
-    --hash=sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1 \
-    --hash=sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9 \
-    --hash=sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864 \
-    --hash=sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914 \
-    --hash=sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee \
-    --hash=sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f \
-    --hash=sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18 \
-    --hash=sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8 \
-    --hash=sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2 \
-    --hash=sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d \
-    --hash=sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b \
-    --hash=sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b \
-    --hash=sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86 \
-    --hash=sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6 \
-    --hash=sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f \
-    --hash=sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb \
-    --hash=sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833 \
-    --hash=sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28 \
-    --hash=sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e \
-    --hash=sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415 \
-    --hash=sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902 \
-    --hash=sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f \
-    --hash=sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d \
-    --hash=sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9 \
-    --hash=sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d \
-    --hash=sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145 \
-    --hash=sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066 \
-    --hash=sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c \
-    --hash=sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1 \
-    --hash=sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a \
-    --hash=sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207 \
-    --hash=sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f \
-    --hash=sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53 \
-    --hash=sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd \
-    --hash=sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134 \
-    --hash=sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85 \
-    --hash=sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9 \
-    --hash=sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5 \
-    --hash=sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94 \
-    --hash=sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509 \
-    --hash=sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51 \
-    --hash=sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872
-    # via
-    #   -r reuse-requirements.in
-    #   jinja2
-python-debian==0.1.44 \
-    --hash=sha256:11bd6f01c46da57982bdd66dd595e2d240feb32a85de3fd37c452102fd0337ab \
-    --hash=sha256:65592fe3b64f6c6c93d94e2d2599db5e0c22831d3bcff07cb7b96d3840b1333e
+jinja2==3.1.2 \
+    --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
+    --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
     # via reuse
-requests==2.26.0 \
-    --hash=sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24 \
-    --hash=sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7
-    # via
-    #   -r reuse-requirements.in
-    #   reuse
-reuse==1.0.0 \
-    --hash=sha256:db3022be2d87f69c8f508b928023de3026f454ce17d01e22f770f7147ac1e8d4 \
-    --hash=sha256:e2605e796311c424465d741ea2a1e1ad03bbb90b921d74750119c331ca5af46e
+license-expression==30.0.0 \
+    --hash=sha256:ad638292aa8493f84354909b517922cb823582c2ce2c4d880e42544a86bea8dd \
+    --hash=sha256:e95325110110eb2b7539ee7773b97a0724d5371ec563cc718c8cac0e38cc40cc
+    # via reuse
+markupsafe==2.1.1 \
+    --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \
+    --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \
+    --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \
+    --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \
+    --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \
+    --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \
+    --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \
+    --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \
+    --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \
+    --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \
+    --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \
+    --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \
+    --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \
+    --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \
+    --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \
+    --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \
+    --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \
+    --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \
+    --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \
+    --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \
+    --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \
+    --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \
+    --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \
+    --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \
+    --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \
+    --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \
+    --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \
+    --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \
+    --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \
+    --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \
+    --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \
+    --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \
+    --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \
+    --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \
+    --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \
+    --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \
+    --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \
+    --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \
+    --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \
+    --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7
+    # via jinja2
+python-debian==0.1.49 \
+    --hash=sha256:880f3bc52e31599f2a9b432bd7691844286825087fccdcf2f6ffd5cd79a26f9f \
+    --hash=sha256:8cf677a30dbcb4be7a99536c17e11308a827a4d22028dc59a67f6c6dd3f0f58c
+    # via reuse
+reuse==1.1.0 \
+    --hash=sha256:7a054f6e372ad02d0b1b07368030fc38746b50ed45f5422a81994e7a88b52f1f \
+    --hash=sha256:b0f3fb9091ff513af04b555d14a4c529ab05f6a575ab192dd9b68244f1e0721d
     # via -r reuse-requirements.in
-urllib3==1.26.10 \
-    --hash=sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec \
-    --hash=sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6
-    # via requests
-
-# The following packages are considered to be unsafe in a requirements file:
-setuptools==59.6.0 \
-    --hash=sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373 \
-    --hash=sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e
-    # via
-    #   -r reuse-requirements.in
-    #   reuse
+setuptools==66.0.0 \
+    --hash=sha256:a78d01d1e2c175c474884671dde039962c9d74c7223db7369771fcf6e29ceeab \
+    --hash=sha256:bd6eb2d6722568de6d14b87c44a96fac54b2a45ff5e940e639979a3d1792adb6
+    # via reuse
index c6d728eb80dd080377bf0a575b30cd828b49ab26..0b06f5e3623e31ac7ce3a892fecaaac3065e96fa 100755 (executable)
@@ -9,11 +9,5 @@ git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git
 cd rust-toolstate
 python3 "../../src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" \
     "$(git log --format=%s -n1 HEAD)" "" ""
-# Only check maintainers if this build is supposed to publish toolstate.
-# Builds that are not supposed to publish don't have the access token.
-if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then
-  TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python3 \
-      "../../src/tools/publish_toolstate.py"
-fi
 cd ..
 rm -rf rust-toolstate
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile
new file mode 100644 (file)
index 0000000..db6032f
--- /dev/null
@@ -0,0 +1,67 @@
+FROM ubuntu:22.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+# NOTE: intentionally installs both python2 and python3 so we can test support for both.
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  gcc-multilib \
+  make \
+  ninja-build \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  python3 \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  llvm-14-tools \
+  llvm-14-dev \
+  libedit-dev \
+  libssl-dev \
+  pkg-config \
+  zlib1g-dev \
+  xz-utils \
+  nodejs \
+  && rm -rf /var/lib/apt/lists/*
+
+# Install powershell (universal package) so we can test x.ps1 on Linux
+RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
+    dpkg -i powershell.deb && \
+    rm -f powershell.deb
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+# We are disabling CI LLVM since this builder is intentionally using a host
+# LLVM, rather than the typical src/llvm-project LLVM.
+ENV NO_DOWNLOAD_CI_LLVM 1
+
+# Using llvm-link-shared due to libffi issues -- see #34486
+ENV RUST_CONFIGURE_ARGS \
+      --build=x86_64-unknown-linux-gnu \
+      --llvm-root=/usr/lib/llvm-14 \
+      --enable-llvm-link-shared \
+      --set rust.thin-lto-import-instr-limit=10
+
+# NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux.
+ENV SCRIPT ../x.py --stage 2 test --exclude src/tools/tidy && \
+           # Run the `mir-opt` tests again but this time for a 32-bit target.
+           # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
+           # both 32-bit and 64-bit outputs updated by the PR author, before
+           # the PR is approved and tested for merging.
+           # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
+           # despite having different output on 32-bit vs 64-bit targets.
+           ../x --stage 2 test tests/mir-opt \
+                             --host='' --target=i686-unknown-linux-gnu && \
+           # Run the UI test suite again, but in `--pass=check` mode
+           #
+           # This is intended to make sure that both `--pass=check` continues to
+           # work.
+           #
+           ../x.ps1 --stage 2 test tests/ui --pass=check \
+                             --host='' --target=i686-unknown-linux-gnu && \
+           # Run tidy at the very end, after all the other tests.
+           python2.7 ../x.py --stage 2 test src/tools/tidy
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile
new file mode 100644 (file)
index 0000000..5219247
--- /dev/null
@@ -0,0 +1,67 @@
+FROM ubuntu:22.10
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+# NOTE: intentionally installs both python2 and python3 so we can test support for both.
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  gcc-multilib \
+  make \
+  ninja-build \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  python3 \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  llvm-15-tools \
+  llvm-15-dev \
+  libedit-dev \
+  libssl-dev \
+  pkg-config \
+  zlib1g-dev \
+  xz-utils \
+  nodejs \
+  && rm -rf /var/lib/apt/lists/*
+
+# Install powershell (universal package) so we can test x.ps1 on Linux
+RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
+    dpkg -i powershell.deb && \
+    rm -f powershell.deb
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+# We are disabling CI LLVM since this builder is intentionally using a host
+# LLVM, rather than the typical src/llvm-project LLVM.
+ENV NO_DOWNLOAD_CI_LLVM 1
+
+# Using llvm-link-shared due to libffi issues -- see #34486
+ENV RUST_CONFIGURE_ARGS \
+      --build=x86_64-unknown-linux-gnu \
+      --llvm-root=/usr/lib/llvm-15 \
+      --enable-llvm-link-shared \
+      --set rust.thin-lto-import-instr-limit=10
+
+# NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux.
+ENV SCRIPT ../x.py --stage 2 test --exclude src/tools/tidy && \
+           # Run the `mir-opt` tests again but this time for a 32-bit target.
+           # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
+           # both 32-bit and 64-bit outputs updated by the PR author, before
+           # the PR is approved and tested for merging.
+           # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
+           # despite having different output on 32-bit vs 64-bit targets.
+           ../x --stage 2 test tests/mir-opt \
+                             --host='' --target=i686-unknown-linux-gnu && \
+           # Run the UI test suite again, but in `--pass=check` mode
+           #
+           # This is intended to make sure that both `--pass=check` continues to
+           # work.
+           #
+           ../x.ps1 --stage 2 test tests/ui --pass=check \
+                             --host='' --target=i686-unknown-linux-gnu && \
+           # Run tidy at the very end, after all the other tests.
+           python2.7 ../x.py --stage 2 test src/tools/tidy
index ba70c62ea3081a96725e3c942e9b21b3d46100f7..4dd6ac274fd5b96dfa24873a8c4e0aea6c262cbc 100644 (file)
@@ -4,28 +4,10 @@ set -ex
 URL=https://dl.google.com/android/repository
 
 download_ndk() {
-    mkdir -p /android/ndk
-    cd /android/ndk
+    mkdir /android/
+    cd /android
     curl -fO $URL/$1
     unzip -q $1
     rm $1
     mv android-ndk-* ndk
 }
-
-make_standalone_toolchain() {
-    # See https://developer.android.com/ndk/guides/standalone_toolchain.htm
-    python3 /android/ndk/ndk/build/tools/make_standalone_toolchain.py \
-        --install-dir /android/ndk/$1-$2 \
-        --arch $1 \
-        --api $2
-}
-
-remove_ndk() {
-    rm -rf /android/ndk/ndk
-}
-
-download_and_make_toolchain() {
-    download_ndk $1 && \
-    make_standalone_toolchain $2 $3 && \
-    remove_ndk
-}
index 8d86590777be3a6972c5aee56490eb474da9f61f..5e676a470a034e2a8ea842da13b4ee2b94761308 100644 (file)
@@ -450,6 +450,16 @@ jobs:
           - name: x86_64-gnu-distcheck
             <<: *job-linux-xl
 
+          - name: x86_64-gnu-llvm-15
+            env:
+              RUST_BACKTRACE: 1
+            <<: *job-linux-xl
+
+          - name: x86_64-gnu-llvm-14
+            env:
+              RUST_BACKTRACE: 1
+            <<: *job-linux-xl
+
           - name: x86_64-gnu-llvm-13
             env:
               RUST_BACKTRACE: 1
@@ -619,9 +629,7 @@ jobs:
 
           - name: i686-mingw-1
             env:
-              RUST_CONFIGURE_ARGS: >-
-                --build=i686-pc-windows-gnu
-                --set llvm.allow-old-toolchain
+              RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
               SCRIPT: make ci-mingw-subset-1
               # We are intentionally allowing an old toolchain on this builder (and that's
               # incompatible with LLVM downloads today).
@@ -631,9 +639,7 @@ jobs:
 
           - name: i686-mingw-2
             env:
-              RUST_CONFIGURE_ARGS: >-
-                --build=i686-pc-windows-gnu
-                --set llvm.allow-old-toolchain
+              RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
               SCRIPT: make ci-mingw-subset-2
               # We are intentionally allowing an old toolchain on this builder (and that's
               # incompatible with LLVM downloads today).
@@ -647,7 +653,6 @@ jobs:
               RUST_CONFIGURE_ARGS: >-
                 --build=x86_64-pc-windows-gnu
                 --enable-profiler
-                --set llvm.allow-old-toolchain
               # We are intentionally allowing an old toolchain on this builder (and that's
               # incompatible with LLVM downloads today).
               NO_DOWNLOAD_CI_LLVM: 1
@@ -660,7 +665,6 @@ jobs:
               RUST_CONFIGURE_ARGS: >-
                 --build=x86_64-pc-windows-gnu
                 --enable-profiler
-                --set llvm.allow-old-toolchain
               # We are intentionally allowing an old toolchain on this builder (and that's
               # incompatible with LLVM downloads today).
               NO_DOWNLOAD_CI_LLVM: 1
@@ -712,7 +716,6 @@ jobs:
                 --build=i686-pc-windows-gnu
                 --enable-full-tools
                 --enable-profiler
-                --set llvm.allow-old-toolchain
               # We are intentionally allowing an old toolchain on this builder (and that's
               # incompatible with LLVM downloads today).
               NO_DOWNLOAD_CI_LLVM: 1
@@ -728,7 +731,6 @@ jobs:
                 --build=x86_64-pc-windows-gnu
                 --enable-full-tools
                 --enable-profiler
-                --set llvm.allow-old-toolchain
               # We are intentionally allowing an old toolchain on this builder (and that's
               # incompatible with LLVM downloads today).
               NO_DOWNLOAD_CI_LLVM: 1
index 1685fbbbbba15435aa5115c1547c9650e5d871f5..7eccb9b86502cdfec0743b2adedaf433827f543c 100755 (executable)
@@ -2,24 +2,6 @@
 # If we need to download a custom MinGW, do so here and set the path
 # appropriately.
 #
-# Here we also do a pretty heinous thing which is to mangle the MinGW
-# installation we just downloaded. Currently, as of this writing, we're using
-# MinGW-w64 builds of gcc, and that's currently at 6.3.0. We use 6.3.0 as it
-# appears to be the first version which contains a fix for #40546, builds
-# randomly failing during LLVM due to ar.exe/ranlib.exe failures.
-#
-# Unfortunately, though, 6.3.0 *also* is the first version of MinGW-w64 builds
-# to contain a regression in gdb (#40184). As a result if we were to use the
-# gdb provided (7.11.1) then we would fail all debuginfo tests.
-#
-# In order to fix spurious failures (pretty high priority) we use 6.3.0. To
-# avoid disabling gdb tests we download an *old* version of gdb, specifically
-# that found inside the 6.2.0 distribution. We then overwrite the 6.3.0 gdb
-# with the 6.2.0 gdb to get tests passing.
-#
-# Note that we don't literally overwrite the gdb.exe binary because it appears
-# to just use gdborig.exe, so that's the binary we deal with instead.
-#
 # Otherwise install MinGW through `pacman`
 
 set -euo pipefail
@@ -27,8 +9,8 @@ IFS=$'\n\t'
 
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
-MINGW_ARCHIVE_32="i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z"
-MINGW_ARCHIVE_64="x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z"
+MINGW_ARCHIVE_32="i686-12.2.0-release-posix-dwarf-rt_v10-rev0.7z"
+MINGW_ARCHIVE_64="x86_64-12.2.0-release-posix-seh-rt_v10-rev0.7z"
 
 if isWindows; then
     case "${CI_JOB_NAME}" in
@@ -66,7 +48,6 @@ if isWindows; then
 
         curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}"
         7z x -y mingw.7z > /dev/null
-        curl -o "${mingw_dir}/bin/gdborig.exe" "${MIRRORS_BASE}/2017-04-20-${bits}bit-gdborig.exe"
         ciCommandAddPath "$(pwd)/${mingw_dir}/bin"
     fi
 fi
index 2bd5d42c9956369132228da6409f0e68da56c51a..2cd1b5593d26dc6a03c20f8619187ad4b2485552 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2bd5d42c9956369132228da6409f0e68da56c51a
+Subproject commit 2cd1b5593d26dc6a03c20f8619187ad4b2485552
index 8ca261268068d80c0969260fff15199bad87b587..960d610e7f33889a2577f5f17c26f0d5c82b30df 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8ca261268068d80c0969260fff15199bad87b587
+Subproject commit 960d610e7f33889a2577f5f17c26f0d5c82b30df
index 3ae62681ff236d5528ef7c8c28ba7c6b2ecc6731..2cb0ed9ba56360949f492f9866afe8c293f9f9da 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3ae62681ff236d5528ef7c8c28ba7c6b2ecc6731
+Subproject commit 2cb0ed9ba56360949f492f9866afe8c293f9f9da
index 8888f9428fe9a48f31de6bd2cef9b9bf80791edc..a9fb7d13eadfcc5f457962731f105b97f9a7474a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8888f9428fe9a48f31de6bd2cef9b9bf80791edc
+Subproject commit a9fb7d13eadfcc5f457962731f105b97f9a7474a
index b3e2a6e6c8a3aae5b5d950c63046f23bae07096d..7352353ae91c48b136d2ca7d03822e1448165e1e 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b3e2a6e6c8a3aae5b5d950c63046f23bae07096d
+Subproject commit 7352353ae91c48b136d2ca7d03822e1448165e1e
index 38fd5c96997631d1ce77b3348e88b7754a8ca63b..da91e25595cc760f117b1eb265748e96ce0c4c6b 100644 (file)
@@ -201,6 +201,8 @@ $ RUSTFLAGS="-C instrument-coverage" \
     cargo test --tests
 ```
 
+> **Note**: The default for `LLVM_PROFILE_FILE` is `default_%m_%p.profraw`. Versions prior to 1.65 had a default of `default.profraw`, so if using those earlier versions, it is recommended to explicitly set `LLVM_PROFILE_FILE="default_%m_%p.profraw"` to avoid having multiple tests overwrite the `.profraw` files.
+
 Make note of the test binary file paths, displayed after the word "`Running`" in the test output:
 
 ```text
diff --git a/src/doc/unstable-book/src/compiler-flags/tiny-const-eval-limit.md b/src/doc/unstable-book/src/compiler-flags/tiny-const-eval-limit.md
new file mode 100644 (file)
index 0000000..51c5fd6
--- /dev/null
@@ -0,0 +1,6 @@
+# `tiny-const-eval-limit`
+
+--------------------
+
+The `-Ztiny-const-eval-limit` compiler flag sets a tiny, non-configurable limit for const eval.
+This flag should only be used by const eval tests in the rustc test suite.
index 7a846d44ad6a8e9484b51aaf41705683feef5742..ff17931115cd038bd164cd171b9567d2768d60b4 100755 (executable)
@@ -14,4 +14,4 @@ ROOT_DIR="$(git rev-parse --show-toplevel)"
 echo "Running pre-push script $ROOT_DIR/x test tidy"
 
 cd "$ROOT_DIR"
-./x test tidy
+CARGOFLAGS="--locked" ./x test tidy
index 4d6f1524732f77453e2ce2489cd3eee1b6f848e8..a302750aa1aea341359cb95ad12d718bc501eec2 100644 (file)
@@ -402,15 +402,13 @@ fn make_final_bounds(
                     bound_params: Vec::new(),
                 })
             })
-            .chain(
-                lifetime_to_bounds.into_iter().filter(|&(_, ref bounds)| !bounds.is_empty()).map(
-                    |(lifetime, bounds)| {
-                        let mut bounds_vec = bounds.into_iter().collect();
-                        self.sort_where_bounds(&mut bounds_vec);
-                        WherePredicate::RegionPredicate { lifetime, bounds: bounds_vec }
-                    },
-                ),
-            )
+            .chain(lifetime_to_bounds.into_iter().filter(|(_, bounds)| !bounds.is_empty()).map(
+                |(lifetime, bounds)| {
+                    let mut bounds_vec = bounds.into_iter().collect();
+                    self.sort_where_bounds(&mut bounds_vec);
+                    WherePredicate::RegionPredicate { lifetime, bounds: bounds_vec }
+                },
+            ))
             .collect()
     }
 
index 4ef5747596bb39a7d4900a393c216f84626f3447..e6b2b2349452acff5b992bfbd0d095d7c6c7c509 100644 (file)
@@ -33,7 +33,7 @@ pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
                     trait_def_id,
                     impl_def_id
                 );
-                let trait_ref = cx.tcx.bound_impl_trait_ref(impl_def_id).unwrap();
+                let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();
                 if !matches!(trait_ref.0.self_ty().kind(), ty::Param(_)) {
                     continue;
                 }
index aad24b4a074927c7d081e9d8fc738bab667d9689..6592692d8b21481333f57efb749f75b1b79d0523 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId};
 use rustc_hir::Mutability;
 use rustc_metadata::creader::{CStore, LoadedMacro};
 use rustc_middle::ty::{self, TyCtxt};
@@ -45,7 +45,7 @@ pub(crate) fn try_inline(
     res: Res,
     name: Symbol,
     attrs: Option<&[ast::Attribute]>,
-    visited: &mut FxHashSet<DefId>,
+    visited: &mut DefIdSet,
 ) -> Option<Vec<clean::Item>> {
     let did = res.opt_def_id()?;
     if did.is_local() {
@@ -162,7 +162,8 @@ pub(crate) fn try_inline(
 pub(crate) fn try_inline_glob(
     cx: &mut DocContext<'_>,
     res: Res,
-    visited: &mut FxHashSet<DefId>,
+    current_mod: LocalDefId,
+    visited: &mut DefIdSet,
     inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
 ) -> Option<Vec<clean::Item>> {
     let did = res.opt_def_id()?;
@@ -172,7 +173,16 @@ pub(crate) fn try_inline_glob(
 
     match res {
         Res::Def(DefKind::Mod, did) => {
-            let mut items = build_module_items(cx, did, visited, inlined_names);
+            // Use the set of module reexports to filter away names that are not actually
+            // reexported by the glob, e.g. because they are shadowed by something else.
+            let reexports = cx
+                .tcx
+                .module_reexports(current_mod)
+                .unwrap_or_default()
+                .iter()
+                .filter_map(|child| child.res.opt_def_id())
+                .collect();
+            let mut items = build_module_items(cx, did, visited, inlined_names, Some(&reexports));
             items.drain_filter(|item| {
                 if let Some(name) = item.name {
                     // If an item with the same type and name already exists,
@@ -241,7 +251,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
 }
 
 fn build_external_function<'tcx>(cx: &mut DocContext<'tcx>, did: DefId) -> Box<clean::Function> {
-    let sig = cx.tcx.fn_sig(did);
+    let sig = cx.tcx.fn_sig(did).subst_identity();
 
     let late_bound_regions = sig.bound_vars().into_iter().filter_map(|var| match var {
         ty::BoundVariableKind::Region(ty::BrNamed(_, name)) if name != kw::UnderscoreLifetime => {
@@ -376,7 +386,7 @@ pub(crate) fn build_impl(
     let _prof_timer = cx.tcx.sess.prof.generic_activity("build_impl");
 
     let tcx = cx.tcx;
-    let associated_trait = tcx.impl_trait_ref(did);
+    let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder);
 
     // Only inline impl if the implemented trait is
     // reachable in rustdoc generated documentation
@@ -558,12 +568,8 @@ pub(crate) fn build_impl(
     ));
 }
 
-fn build_module(
-    cx: &mut DocContext<'_>,
-    did: DefId,
-    visited: &mut FxHashSet<DefId>,
-) -> clean::Module {
-    let items = build_module_items(cx, did, visited, &mut FxHashSet::default());
+fn build_module(cx: &mut DocContext<'_>, did: DefId, visited: &mut DefIdSet) -> clean::Module {
+    let items = build_module_items(cx, did, visited, &mut FxHashSet::default(), None);
 
     let span = clean::Span::new(cx.tcx.def_span(did));
     clean::Module { items, span }
@@ -572,8 +578,9 @@ fn build_module(
 fn build_module_items(
     cx: &mut DocContext<'_>,
     did: DefId,
-    visited: &mut FxHashSet<DefId>,
+    visited: &mut DefIdSet,
     inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
+    allowed_def_ids: Option<&DefIdSet>,
 ) -> Vec<clean::Item> {
     let mut items = Vec::new();
 
@@ -583,6 +590,11 @@ fn build_module_items(
     for &item in cx.tcx.module_children(did).iter() {
         if item.vis.is_public() {
             let res = item.res.expect_non_local();
+            if let Some(def_id) = res.opt_def_id()
+                && let Some(allowed_def_ids) = allowed_def_ids
+                && !allowed_def_ids.contains(&def_id) {
+                continue;
+            }
             if let Some(def_id) = res.mod_def_id() {
                 // If we're inlining a glob import, it's possible to have
                 // two distinct modules with the same name. We don't want to
index 025a4379f45a31a289177d6daad62200c3aa6302..e2ced191a00c0e267eaf71e3d353eed379d7bd6b 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
 use rustc_hir::PredicateOrigin;
 use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
@@ -116,7 +116,8 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
         }
     });
 
-    Item::from_hir_id_and_parts(doc.id, Some(doc.name), ModuleItem(Module { items, span }), cx)
+    let kind = ModuleItem(Module { items, span });
+    Item::from_def_id_and_parts(doc.def_id.to_def_id(), Some(doc.name), kind, cx)
 }
 
 fn clean_generic_bound<'tcx>(
@@ -382,13 +383,10 @@ fn clean_middle_term<'tcx>(
 fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term {
     match term {
         hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)),
-        hir::Term::Const(c) => {
-            let def_id = cx.tcx.hir().local_def_id(c.hir_id);
-            Term::Constant(clean_middle_const(
-                ty::Binder::dummy(ty::Const::from_anon_const(cx.tcx, def_id)),
-                cx,
-            ))
-        }
+        hir::Term::Const(c) => Term::Constant(clean_middle_const(
+            ty::Binder::dummy(ty::Const::from_anon_const(cx.tcx, c.def_id)),
+            cx,
+        )),
     }
 }
 
@@ -506,7 +504,9 @@ fn clean_generic_param_def<'tcx>(
                     Some(def.def_id),
                 )),
                 default: match has_default {
-                    true => Some(Box::new(cx.tcx.const_param_default(def.def_id).to_string())),
+                    true => Some(Box::new(
+                        cx.tcx.const_param_default(def.def_id).subst_identity().to_string(),
+                    )),
                     false => None,
                 },
             },
@@ -521,12 +521,11 @@ fn clean_generic_param<'tcx>(
     generics: Option<&hir::Generics<'tcx>>,
     param: &hir::GenericParam<'tcx>,
 ) -> GenericParamDef {
-    let did = cx.tcx.hir().local_def_id(param.hir_id);
     let (name, kind) = match param.kind {
         hir::GenericParamKind::Lifetime { .. } => {
             let outlives = if let Some(generics) = generics {
                 generics
-                    .outlives_for_param(did)
+                    .outlives_for_param(param.def_id)
                     .filter(|bp| !bp.in_where_clause)
                     .flat_map(|bp| bp.bounds)
                     .map(|bound| match bound {
@@ -542,7 +541,7 @@ fn clean_generic_param<'tcx>(
         hir::GenericParamKind::Type { ref default, synthetic } => {
             let bounds = if let Some(generics) = generics {
                 generics
-                    .bounds_for_param(did)
+                    .bounds_for_param(param.def_id)
                     .filter(|bp| bp.origin != PredicateOrigin::WhereClause)
                     .flat_map(|bp| bp.bounds)
                     .filter_map(|x| clean_generic_bound(x, cx))
@@ -553,7 +552,7 @@ fn clean_generic_param<'tcx>(
             (
                 param.name.ident().name,
                 GenericParamDefKind::Type {
-                    did: did.to_def_id(),
+                    did: param.def_id.to_def_id(),
                     bounds,
                     default: default.map(|t| clean_ty(t, cx)).map(Box::new),
                     synthetic,
@@ -563,12 +562,10 @@ fn clean_generic_param<'tcx>(
         hir::GenericParamKind::Const { ty, default } => (
             param.name.ident().name,
             GenericParamDefKind::Const {
-                did: did.to_def_id(),
+                did: param.def_id.to_def_id(),
                 ty: Box::new(clean_ty(ty, cx)),
-                default: default.map(|ct| {
-                    let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
-                    Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
-                }),
+                default: default
+                    .map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())),
             },
         ),
     };
@@ -1228,7 +1225,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
             }
         }
         ty::AssocKind::Fn => {
-            let sig = tcx.fn_sig(assoc_item.def_id);
+            let sig = tcx.fn_sig(assoc_item.def_id).subst_identity();
 
             let late_bound_regions = sig.bound_vars().into_iter().filter_map(|var| match var {
                 ty::BoundVariableKind::Region(ty::BrNamed(_, name))
@@ -1526,7 +1523,7 @@ fn maybe_expand_private_type_alias<'tcx>(
     let hir::ItemKind::TyAlias(ty, generics) = alias else { return None };
 
     let provided_params = &path.segments.last().expect("segments were empty");
-    let mut substs = FxHashMap::default();
+    let mut substs = DefIdMap::default();
     let generic_args = provided_params.args();
 
     let mut indices: hir::GenericParamCount = Default::default();
@@ -1545,18 +1542,16 @@ fn maybe_expand_private_type_alias<'tcx>(
                     _ => None,
                 });
                 if let Some(lt) = lifetime {
-                    let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
                     let cleaned = if !lt.is_anonymous() {
                         clean_lifetime(lt, cx)
                     } else {
                         Lifetime::elided()
                     };
-                    substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
+                    substs.insert(param.def_id.to_def_id(), SubstParam::Lifetime(cleaned));
                 }
                 indices.lifetimes += 1;
             }
             hir::GenericParamKind::Type { ref default, .. } => {
-                let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
                 let mut j = 0;
                 let type_ = generic_args.args.iter().find_map(|arg| match arg {
                     hir::GenericArg::Type(ty) => {
@@ -1569,17 +1564,14 @@ fn maybe_expand_private_type_alias<'tcx>(
                     _ => None,
                 });
                 if let Some(ty) = type_ {
-                    substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx)));
+                    substs.insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx)));
                 } else if let Some(default) = *default {
-                    substs.insert(
-                        ty_param_def_id.to_def_id(),
-                        SubstParam::Type(clean_ty(default, cx)),
-                    );
+                    substs
+                        .insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(default, cx)));
                 }
                 indices.types += 1;
             }
             hir::GenericParamKind::Const { .. } => {
-                let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
                 let mut j = 0;
                 let const_ = generic_args.args.iter().find_map(|arg| match arg {
                     hir::GenericArg::Const(ct) => {
@@ -1593,7 +1585,7 @@ fn maybe_expand_private_type_alias<'tcx>(
                 });
                 if let Some(ct) = const_ {
                     substs.insert(
-                        const_param_def_id.to_def_id(),
+                        param.def_id.to_def_id(),
                         SubstParam::Constant(clean_const(ct, cx)),
                     );
                 }
@@ -1621,7 +1613,6 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
             let length = match length {
                 hir::ArrayLen::Infer(_, _) => "_".to_string(),
                 hir::ArrayLen::Body(anon_const) => {
-                    let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id);
                     // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
                     // as we currently do not supply the parent generics to anonymous constants
                     // but do allow `ConstKind::Param`.
@@ -1629,8 +1620,8 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
                     // `const_eval_poly` tries to first substitute generic parameters which
                     // results in an ICE while manually constructing the constant and using `eval`
                     // does nothing for `ConstKind::Param`.
-                    let ct = ty::Const::from_anon_const(cx.tcx, def_id);
-                    let param_env = cx.tcx.param_env(def_id);
+                    let ct = ty::Const::from_anon_const(cx.tcx, anon_const.def_id);
+                    let param_env = cx.tcx.param_env(anon_const.def_id);
                     print_const(cx, ct.eval(cx.tcx, param_env))
                 }
             };
@@ -1852,6 +1843,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
         ty::Bound(..) => panic!("Bound"),
         ty::Placeholder(..) => panic!("Placeholder"),
         ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
+        ty::GeneratorWitnessMIR(..) => panic!("GeneratorWitnessMIR"),
         ty::Infer(..) => panic!("Infer"),
         ty::Error(_) => rustc_errors::FatalError.raise(),
     }
@@ -1926,8 +1918,7 @@ fn clean_middle_opaque_bounds<'tcx>(
 }
 
 pub(crate) fn clean_field<'tcx>(field: &hir::FieldDef<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
-    let def_id = cx.tcx.hir().local_def_id(field.hir_id).to_def_id();
-    clean_field_with_def_id(def_id, field.ident.name, clean_ty(field.ty, cx), cx)
+    clean_field_with_def_id(field.def_id.to_def_id(), field.ident.name, clean_ty(field.ty, cx), cx)
 }
 
 pub(crate) fn clean_middle_field<'tcx>(field: &ty::FieldDef, cx: &mut DocContext<'tcx>) -> Item {
@@ -1977,10 +1968,8 @@ fn clean_variant_data<'tcx>(
     disr_expr: &Option<hir::AnonConst>,
     cx: &mut DocContext<'tcx>,
 ) -> Variant {
-    let discriminant = disr_expr.map(|disr| Discriminant {
-        expr: Some(disr.body),
-        value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
-    });
+    let discriminant = disr_expr
+        .map(|disr| Discriminant { expr: Some(disr.body), value: disr.def_id.to_def_id() });
 
     let kind = match variant {
         hir::VariantData::Struct(..) => VariantKind::Struct(VariantStruct {
@@ -2065,12 +2054,12 @@ struct OneLevelVisitor<'hir> {
     map: rustc_middle::hir::map::Map<'hir>,
     item: Option<&'hir hir::Item<'hir>>,
     looking_for: Ident,
-    target_hir_id: hir::HirId,
+    target_def_id: LocalDefId,
 }
 
 impl<'hir> OneLevelVisitor<'hir> {
-    fn new(map: rustc_middle::hir::map::Map<'hir>, target_hir_id: hir::HirId) -> Self {
-        Self { map, item: None, looking_for: Ident::empty(), target_hir_id }
+    fn new(map: rustc_middle::hir::map::Map<'hir>, target_def_id: LocalDefId) -> Self {
+        Self { map, item: None, looking_for: Ident::empty(), target_def_id }
     }
 
     fn reset(&mut self, looking_for: Ident) {
@@ -2090,7 +2079,7 @@ fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
         if self.item.is_none()
             && item.ident == self.looking_for
             && matches!(item.kind, hir::ItemKind::Use(_, _))
-            || item.hir_id() == self.target_hir_id
+            || item.owner_id.def_id == self.target_def_id
         {
             self.item = Some(item);
         }
@@ -2104,15 +2093,17 @@ fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
 fn get_all_import_attributes<'hir>(
     mut item: &hir::Item<'hir>,
     tcx: TyCtxt<'hir>,
-    target_hir_id: hir::HirId,
+    target_def_id: LocalDefId,
     attributes: &mut Vec<ast::Attribute>,
 ) {
     let hir_map = tcx.hir();
-    let mut visitor = OneLevelVisitor::new(hir_map, target_hir_id);
+    let mut visitor = OneLevelVisitor::new(hir_map, target_def_id);
+    let mut visited = FxHashSet::default();
     // If the item is an import and has at least a path with two parts, we go into it.
     while let hir::ItemKind::Use(path, _) = item.kind &&
         path.segments.len() > 1 &&
-        let hir::def::Res::Def(_, def_id) = path.segments[path.segments.len() - 2].res
+        let hir::def::Res::Def(_, def_id) = path.segments[path.segments.len() - 2].res &&
+        visited.insert(def_id)
     {
         if let Some(hir::Node::Item(parent_item)) = hir_map.get_if_local(def_id) {
             // We add the attributes from this import into the list.
@@ -2136,7 +2127,7 @@ fn clean_maybe_renamed_item<'tcx>(
     cx: &mut DocContext<'tcx>,
     item: &hir::Item<'tcx>,
     renamed: Option<Symbol>,
-    import_id: Option<hir::HirId>,
+    import_id: Option<LocalDefId>,
 ) -> Vec<Item> {
     use hir::ItemKind;
 
@@ -2181,7 +2172,7 @@ fn clean_maybe_renamed_item<'tcx>(
                 generics: clean_generics(generics, cx),
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
-            ItemKind::Impl(impl_) => return clean_impl(impl_, item.hir_id(), cx),
+            ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
             // proc macros can have a name set by attributes
             ItemKind::Fn(ref sig, generics, body_id) => {
                 clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
@@ -2216,10 +2207,10 @@ fn clean_maybe_renamed_item<'tcx>(
 
         let mut extra_attrs = Vec::new();
         if let Some(hir::Node::Item(use_node)) =
-            import_id.and_then(|hir_id| cx.tcx.hir().find(hir_id))
+            import_id.and_then(|def_id| cx.tcx.hir().find_by_def_id(def_id))
         {
             // We get all the various imports' attributes.
-            get_all_import_attributes(use_node, cx.tcx, item.hir_id(), &mut extra_attrs);
+            get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut extra_attrs);
         }
 
         if !extra_attrs.is_empty() {
@@ -2242,12 +2233,12 @@ fn clean_maybe_renamed_item<'tcx>(
 
 fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
     let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx));
-    Item::from_hir_id_and_parts(variant.hir_id, Some(variant.ident.name), kind, cx)
+    Item::from_def_id_and_parts(variant.def_id.to_def_id(), Some(variant.ident.name), kind, cx)
 }
 
 fn clean_impl<'tcx>(
     impl_: &hir::Impl<'tcx>,
-    hir_id: hir::HirId,
+    def_id: LocalDefId,
     cx: &mut DocContext<'tcx>,
 ) -> Vec<Item> {
     let tcx = cx.tcx;
@@ -2258,7 +2249,6 @@ fn clean_impl<'tcx>(
         .iter()
         .map(|ii| clean_impl_item(tcx.hir().impl_item(ii.id), cx))
         .collect::<Vec<_>>();
-    let def_id = tcx.hir().local_def_id(hir_id);
 
     // If this impl block is an implementation of the Deref trait, then we
     // need to try inlining the target's inherent impl blocks as well.
@@ -2287,7 +2277,7 @@ fn clean_impl<'tcx>(
                 ImplKind::Normal
             },
         }));
-        Item::from_hir_id_and_parts(hir_id, None, kind, cx)
+        Item::from_def_id_and_parts(def_id.to_def_id(), None, kind, cx)
     };
     if let Some(type_alias) = type_alias {
         ret.push(make_item(trait_.clone(), type_alias, items.clone()));
@@ -2319,7 +2309,7 @@ fn clean_extern_crate<'tcx>(
 
     let krate_owner_def_id = krate.owner_id.to_def_id();
     if please_inline {
-        let mut visited = FxHashSet::default();
+        let mut visited = DefIdSet::default();
 
         let res = Res::Def(DefKind::Mod, crate_def_id);
 
@@ -2438,8 +2428,9 @@ fn clean_use_statement_inner<'tcx>(
     let path = clean_path(path, cx);
     let inner = if kind == hir::UseKind::Glob {
         if !denied {
-            let mut visited = FxHashSet::default();
-            if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited, inlined_names)
+            let mut visited = DefIdSet::default();
+            if let Some(items) =
+                inline::try_inline_glob(cx, path.res, current_mod, &mut visited, inlined_names)
             {
                 return items;
             }
@@ -2456,7 +2447,7 @@ fn clean_use_statement_inner<'tcx>(
             }
         }
         if !denied {
-            let mut visited = FxHashSet::default();
+            let mut visited = DefIdSet::default();
             let import_def_id = import.owner_id.to_def_id();
 
             if let Some(mut items) = inline::try_inline(
@@ -2507,8 +2498,8 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
             hir::ForeignItemKind::Type => ForeignTypeItem,
         };
 
-        Item::from_hir_id_and_parts(
-            item.hir_id(),
+        Item::from_def_id_and_parts(
+            item.owner_id.def_id.to_def_id(),
             Some(renamed.unwrap_or(item.ident.name)),
             kind,
             cx,
index e96a9bab72620970b87e9ab4f3d8acc0839ec664..dbbc25739aa078fa002422c3439b1376c6224283 100644 (file)
@@ -46,7 +46,7 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> ThinVec<WP
 
     // Look for equality predicates on associated types that can be merged into
     // general bound predicates.
-    equalities.retain(|&(ref lhs, ref rhs, ref bound_params)| {
+    equalities.retain(|(lhs, rhs, bound_params)| {
         let Some((ty, trait_did, name)) = lhs.projection() else { return true; };
         let Some((bounds, _)) = tybounds.get_mut(ty) else { return true };
         let bound_params = bound_params
index 87de41fde63c5e27ce9b4b333c81814347eaf33d..85dd3881593aca0969e2791a3305888390e26d43 100644 (file)
@@ -439,17 +439,6 @@ pub(crate) fn doc_value(&self) -> Option<String> {
         self.attrs.doc_value()
     }
 
-    /// Convenience wrapper around [`Self::from_def_id_and_parts`] which converts
-    /// `hir_id` to a [`DefId`]
-    pub(crate) fn from_hir_id_and_parts(
-        hir_id: hir::HirId,
-        name: Option<Symbol>,
-        kind: ItemKind,
-        cx: &mut DocContext<'_>,
-    ) -> Item {
-        Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx)
-    }
-
     pub(crate) fn from_def_id_and_parts(
         def_id: DefId,
         name: Option<Symbol>,
@@ -665,7 +654,7 @@ fn build_fn_header(
             tcx: TyCtxt<'_>,
             asyncness: hir::IsAsync,
         ) -> hir::FnHeader {
-            let sig = tcx.fn_sig(def_id);
+            let sig = tcx.fn_sig(def_id).skip_binder();
             let constness =
                 if tcx.is_const_fn(def_id) && is_unstable_const_fn(tcx, def_id).is_none() {
                     hir::Constness::Const
@@ -677,7 +666,7 @@ fn build_fn_header(
         let header = match *self.kind {
             ItemKind::ForeignFunctionItem(_) => {
                 let def_id = self.item_id.as_def_id().unwrap();
-                let abi = tcx.fn_sig(def_id).abi();
+                let abi = tcx.fn_sig(def_id).skip_binder().abi();
                 hir::FnHeader {
                     unsafety: if abi == Abi::RustIntrinsic {
                         intrinsic_operation_unsafety(tcx, self.item_id.as_def_id().unwrap())
@@ -2416,10 +2405,7 @@ pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
 
     pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
         match *self {
-            ConstantKind::TyConst { .. } => false,
-            ConstantKind::Extern { def_id } => def_id.as_local().map_or(false, |def_id| {
-                is_literal_expr(tcx, tcx.hir().local_def_id_to_hir_id(def_id))
-            }),
+            ConstantKind::TyConst { .. } | ConstantKind::Extern { .. } => false,
             ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
                 is_literal_expr(tcx, body.hir_id)
             }
@@ -2498,14 +2484,7 @@ pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self
     }
 
     pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
-        match self.source.did {
-            Some(did) => tcx
-                .get_attrs(did, sym::doc)
-                .filter_map(ast::Attribute::meta_item_list)
-                .flatten()
-                .has_word(sym::hidden),
-            None => false,
-        }
+        self.source.did.map_or(false, |did| tcx.is_doc_hidden(did))
     }
 }
 
index a12f764fa8e3b739404df7937b83969a10e6bb8f..ca3a70c7236feb2a617527c19712bb65b81882c5 100644 (file)
 pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
     let module = crate::visit_ast::RustdocVisitor::new(cx).visit();
 
-    for &cnum in cx.tcx.crates(()) {
-        // Analyze doc-reachability for extern items
-        crate::visit_lib::lib_embargo_visit_item(cx, cnum.as_def_id());
-    }
-
     // Clean the crate, translating the entire librustc_ast AST to one that is
     // understood by rustdoc.
     let mut module = clean_doc_module(&module, cx);
index da0df596c41e34f7ca88e07b1e7b0811b75ed22d..0ce43f7db8e8b0d9d8fb5cd768141da3a27cd023 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_errors::json::JsonEmitter;
 use rustc_feature::UnstableFeatures;
 use rustc_hir::def::{Namespace, Res};
-use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
+use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{HirId, Path, TraitCandidate};
 use rustc_interface::interface;
@@ -41,6 +41,7 @@ pub(crate) struct ResolverCaches {
     pub(crate) traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
     pub(crate) all_trait_impls: Option<Vec<DefId>>,
     pub(crate) all_macro_rules: FxHashMap<Symbol, Res<NodeId>>,
+    pub(crate) extern_doc_reachable: DefIdSet,
 }
 
 pub(crate) struct DocContext<'tcx> {
@@ -60,11 +61,11 @@ pub(crate) struct DocContext<'tcx> {
     pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, clean::Trait>>>,
     /// Used while populating `external_traits` to ensure we don't process the same trait twice at
     /// the same time.
-    pub(crate) active_extern_traits: FxHashSet<DefId>,
+    pub(crate) active_extern_traits: DefIdSet,
     // The current set of parameter substitutions,
     // for expanding type aliases at the HIR level:
     /// Table `DefId` of type, lifetime, or const parameter -> substituted type, lifetime, or const
-    pub(crate) substs: FxHashMap<DefId, clean::SubstParam>,
+    pub(crate) substs: DefIdMap<clean::SubstParam>,
     /// Table synthetic type parameter for `impl Trait` in argument position -> bounds
     pub(crate) impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
     /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
@@ -108,11 +109,7 @@ pub(crate) fn enter_resolver<F, R>(&self, f: F) -> R
 
     /// Call the closure with the given parameters set as
     /// the substitutions for a type alias' RHS.
-    pub(crate) fn enter_alias<F, R>(
-        &mut self,
-        substs: FxHashMap<DefId, clean::SubstParam>,
-        f: F,
-    ) -> R
+    pub(crate) fn enter_alias<F, R>(&mut self, substs: DefIdMap<clean::SubstParam>, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R,
     {
@@ -225,7 +222,6 @@ pub(crate) fn create_config(
     // Add the doc cfg into the doc build.
     cfgs.push("doc".to_string());
 
-    let cpath = Some(input.clone());
     let input = Input::File(input);
 
     // By default, rustdoc ignores all lints.
@@ -277,7 +273,6 @@ pub(crate) fn create_config(
         crate_cfg: interface::parse_cfgspecs(cfgs),
         crate_check_cfg: interface::parse_check_cfg(check_cfgs),
         input,
-        input_path: cpath,
         output_file: None,
         output_dir: None,
         file_loader: None,
@@ -369,6 +364,10 @@ pub(crate) fn run_global_ctxt(
         show_coverage,
     };
 
+    ctxt.cache
+        .effective_visibilities
+        .init(mem::take(&mut ctxt.resolver_caches.extern_doc_reachable));
+
     // Small hack to force the Sized trait to be present.
     //
     // Note that in case of `#![no_core]`, the trait is not available.
index d1b6d470e86ce91da866d11d89abbed6dc1622be..37a1005cba1fc82a97ef7690805aac5a121c5a3b 100644 (file)
@@ -2,10 +2,8 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError};
-use rustc_hir as hir;
-use rustc_hir::def_id::LOCAL_CRATE;
-use rustc_hir::intravisit;
-use rustc_hir::{HirId, CRATE_HIR_ID};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::{self as hir, intravisit, CRATE_HIR_ID};
 use rustc_interface::interface;
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
@@ -95,7 +93,6 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
         crate_cfg: interface::parse_cfgspecs(cfgs),
         crate_check_cfg: interface::parse_check_cfg(options.check_cfgs.clone()),
         input,
-        input_path: None,
         output_file: None,
         output_dir: None,
         file_loader: None,
@@ -141,7 +138,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
                     };
                     hir_collector.visit_testable(
                         "".to_string(),
-                        CRATE_HIR_ID,
+                        CRATE_DEF_ID,
                         tcx.hir().span(CRATE_HIR_ID),
                         |this| tcx.hir().walk_toplevel_module(this),
                     );
@@ -1215,11 +1212,11 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
     fn visit_testable<F: FnOnce(&mut Self)>(
         &mut self,
         name: String,
-        hir_id: HirId,
+        def_id: LocalDefId,
         sp: Span,
         nested: F,
     ) {
-        let ast_attrs = self.tcx.hir().attrs(hir_id);
+        let ast_attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id));
         if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) {
             if !cfg.matches(&self.sess.parse_sess, Some(self.tcx.features())) {
                 return;
@@ -1248,7 +1245,7 @@ fn visit_testable<F: FnOnce(&mut Self)>(
                 self.collector.enable_per_target_ignores,
                 Some(&crate::html::markdown::ExtraInfo::new(
                     self.tcx,
-                    hir_id,
+                    def_id.to_def_id(),
                     span_of_attrs(&attrs).unwrap_or(sp),
                 )),
             );
@@ -1277,37 +1274,37 @@ fn visit_item(&mut self, item: &'hir hir::Item<'_>) {
             _ => item.ident.to_string(),
         };
 
-        self.visit_testable(name, item.hir_id(), item.span, |this| {
+        self.visit_testable(name, item.owner_id.def_id, item.span, |this| {
             intravisit::walk_item(this, item);
         });
     }
 
     fn visit_trait_item(&mut self, item: &'hir hir::TraitItem<'_>) {
-        self.visit_testable(item.ident.to_string(), item.hir_id(), item.span, |this| {
+        self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| {
             intravisit::walk_trait_item(this, item);
         });
     }
 
     fn visit_impl_item(&mut self, item: &'hir hir::ImplItem<'_>) {
-        self.visit_testable(item.ident.to_string(), item.hir_id(), item.span, |this| {
+        self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| {
             intravisit::walk_impl_item(this, item);
         });
     }
 
     fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem<'_>) {
-        self.visit_testable(item.ident.to_string(), item.hir_id(), item.span, |this| {
+        self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| {
             intravisit::walk_foreign_item(this, item);
         });
     }
 
     fn visit_variant(&mut self, v: &'hir hir::Variant<'_>) {
-        self.visit_testable(v.ident.to_string(), v.hir_id, v.span, |this| {
+        self.visit_testable(v.ident.to_string(), v.def_id, v.span, |this| {
             intravisit::walk_variant(this, v);
         });
     }
 
     fn visit_field_def(&mut self, f: &'hir hir::FieldDef<'_>) {
-        self.visit_testable(f.ident.to_string(), f.hir_id, f.span, |this| {
+        self.visit_testable(f.ident.to_string(), f.def_id, f.span, |this| {
             intravisit::walk_field_def(this, f);
         });
     }
index d027fb6e8763cad8fdc3d1ffd6a237111b5de891..24752cddb337ceeade25dcacdde3e9370d2af23e 100644 (file)
@@ -1,7 +1,7 @@
 use std::mem;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::Symbol;
 
@@ -33,7 +33,7 @@ pub(crate) struct Cache {
     ///
     /// The values of the map are a list of implementations and documentation
     /// found on that implementation.
-    pub(crate) impls: FxHashMap<DefId, Vec<Impl>>,
+    pub(crate) impls: DefIdMap<Vec<Impl>>,
 
     /// Maintains a mapping of local crate `DefId`s to the fully qualified name
     /// and "short type description" of that node. This is used when generating
@@ -56,7 +56,7 @@ pub(crate) struct Cache {
     /// to the path used if the corresponding type is inlined. By
     /// doing this, we can detect duplicate impls on a trait page, and only display
     /// the impl for the inlined type.
-    pub(crate) exact_paths: FxHashMap<DefId, Vec<Symbol>>,
+    pub(crate) exact_paths: DefIdMap<Vec<Symbol>>,
 
     /// This map contains information about all known traits of this crate.
     /// Implementations of a crate should inherit the documentation of the
@@ -127,7 +127,7 @@ pub(crate) struct Cache {
 struct CacheBuilder<'a, 'tcx> {
     cache: &'a mut Cache,
     /// This field is used to prevent duplicated impl blocks.
-    impl_ids: FxHashMap<DefId, FxHashSet<DefId>>,
+    impl_ids: DefIdMap<DefIdSet>,
     tcx: TyCtxt<'tcx>,
 }
 
@@ -173,7 +173,7 @@ pub(crate) fn populate(cx: &mut DocContext<'_>, mut krate: clean::Crate) -> clea
 
         let (krate, mut impl_ids) = {
             let mut cache_builder =
-                CacheBuilder { tcx, cache: &mut cx.cache, impl_ids: FxHashMap::default() };
+                CacheBuilder { tcx, cache: &mut cx.cache, impl_ids: Default::default() };
             krate = cache_builder.fold_crate(krate);
             (krate, cache_builder.impl_ids)
         };
@@ -242,7 +242,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         }
 
         // Index this method for searching later on.
-        if let Some(ref s) = item.name.or_else(|| {
+        if let Some(s) = item.name.or_else(|| {
             if item.is_stripped() {
                 None
             } else if let clean::ImportItem(ref i) = *item.kind &&
@@ -296,7 +296,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                             // for where the type was defined. On the other
                             // hand, `paths` always has the right
                             // information if present.
-                            Some(&(ref fqp, _)) => Some(&fqp[..fqp.len() - 1]),
+                            Some((fqp, _)) => Some(&fqp[..fqp.len() - 1]),
                             None => None,
                         };
                         ((did, path), true)
@@ -317,14 +317,15 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                             short_markdown_summary(x.as_str(), &item.link_names(self.cache))
                         });
                         let ty = item.type_();
-                        let name = s.to_string();
-                        if ty != ItemType::StructField || u16::from_str_radix(&name, 10).is_err() {
+                        if ty != ItemType::StructField
+                            || u16::from_str_radix(s.as_str(), 10).is_err()
+                        {
                             // In case this is a field from a tuple struct, we don't add it into
                             // the search index because its name is something like "0", which is
                             // not useful for rustdoc search.
                             self.cache.search_index.push(IndexItem {
                                 ty,
-                                name,
+                                name: s,
                                 path: join_with_double_colon(path),
                                 desc,
                                 parent,
index 5ad24bf2681332b83efb73a192b345bfa4993113..33404a76835975da4e656f3f8bff6f5952116202 100644 (file)
@@ -569,7 +569,7 @@ fn generate_macro_def_id_path(
     root_path: Option<&str>,
 ) -> Result<(String, ItemType, Vec<Symbol>), HrefError> {
     let tcx = cx.shared.tcx;
-    let crate_name = tcx.crate_name(def_id.krate).to_string();
+    let crate_name = tcx.crate_name(def_id.krate);
     let cache = cx.cache();
 
     let fqp: Vec<Symbol> = tcx
@@ -584,7 +584,7 @@ fn generate_macro_def_id_path(
             }
         })
         .collect();
-    let mut relative = fqp.iter().map(|elem| elem.to_string());
+    let mut relative = fqp.iter().copied();
     let cstore = CStore::from_tcx(tcx);
     // We need this to prevent a `panic` when this function is used from intra doc links...
     if !cstore.has_crate_data(def_id.krate) {
@@ -602,9 +602,9 @@ fn generate_macro_def_id_path(
     };
 
     let mut path = if is_macro_2 {
-        once(crate_name.clone()).chain(relative).collect()
+        once(crate_name).chain(relative).collect()
     } else {
-        vec![crate_name.clone(), relative.next_back().unwrap()]
+        vec![crate_name, relative.next_back().unwrap()]
     };
     if path.len() < 2 {
         // The minimum we can have is the crate name followed by the macro name. If shorter, then
@@ -614,17 +614,22 @@ fn generate_macro_def_id_path(
     }
 
     if let Some(last) = path.last_mut() {
-        *last = format!("macro.{}.html", last);
+        *last = Symbol::intern(&format!("macro.{}.html", last.as_str()));
     }
 
     let url = match cache.extern_locations[&def_id.krate] {
         ExternalLocation::Remote(ref s) => {
             // `ExternalLocation::Remote` always end with a `/`.
-            format!("{}{}", s, path.join("/"))
+            format!("{}{}", s, path.iter().map(|p| p.as_str()).join("/"))
         }
         ExternalLocation::Local => {
             // `root_path` always end with a `/`.
-            format!("{}{}/{}", root_path.unwrap_or(""), crate_name, path.join("/"))
+            format!(
+                "{}{}/{}",
+                root_path.unwrap_or(""),
+                crate_name,
+                path.iter().map(|p| p.as_str()).join("/")
+            )
         }
         ExternalLocation::Unknown => {
             debug!("crate {} not in cache when linkifying macros", crate_name);
@@ -957,7 +962,7 @@ fn fmt_type<'cx>(
         clean::Tuple(ref typs) => {
             match &typs[..] {
                 &[] => primitive_link(f, PrimitiveType::Unit, "()", cx),
-                &[ref one] => {
+                [one] => {
                     if let clean::Generic(name) = one {
                         primitive_link(f, PrimitiveType::Tuple, &format!("({name},)"), cx)
                     } else {
@@ -1050,7 +1055,7 @@ fn fmt_type<'cx>(
                 _ => String::new(),
             };
             let m = mutability.print_with_space();
-            let amp = if f.alternate() { "&".to_string() } else { "&amp;".to_string() };
+            let amp = if f.alternate() { "&" } else { "&amp;" };
             match **ty {
                 clean::DynTrait(ref bounds, ref trait_lt)
                     if bounds.len() > 1 || trait_lt.is_some() =>
@@ -1059,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 bbdc91c8d2ec8fbbe3b686002cd0bf34e249c32b..4c8db2c6784a52267c06cfb68db3c2382296624c 100644 (file)
@@ -61,14 +61,14 @@ pub(super) fn finish(mut self) -> String {
     /// and returns [`ControlFlow::Break`].
     pub(super) fn push(&mut self, text: &str) -> ControlFlow<(), ()> {
         if self.len + text.len() > self.limit {
-            return ControlFlow::BREAK;
+            return ControlFlow::Break(());
         }
 
         self.flush_queue();
         write!(self.buf, "{}", Escape(text)).unwrap();
         self.len += text.len();
 
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     }
 
     /// Open an HTML tag.
index 2d02b8a16da67415c0e6b8f8016a318bfe117f89..2185c034890fa3de43c28546d9a6844f465a2d99 100644 (file)
@@ -83,7 +83,7 @@ fn past_the_limit() {
         buf.push("word#")?;
         buf.push(&n.to_string())?;
         buf.close_tag();
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     });
     buf.close_tag();
     assert_eq!(
index aeaee524fd4532b820f130d04ccb7912ceb68411..00e3f859bfcb30dd62dd1f1cde00a9ba41a294ea 100644 (file)
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
-use rustc_hir::HirId;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::edition::Edition;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 
 use once_cell::sync::Lazy;
 use std::borrow::Cow;
@@ -198,7 +197,7 @@ fn slugify(c: char) -> Option<char> {
 
 #[derive(Clone, Debug)]
 pub struct Playground {
-    pub crate_name: Option<String>,
+    pub crate_name: Option<Symbol>,
     pub url: String,
 }
 
@@ -290,13 +289,15 @@ fn next(&mut self) -> Option<Self::Item> {
                 .map(|l| map_line(l).for_code())
                 .intersperse("\n".into())
                 .collect::<String>();
-            let krate = krate.as_ref().map(|s| &**s);
+            let krate = krate.as_ref().map(|s| s.as_str());
             let (test, _, _) =
                 doctest::make_test(&test, krate, false, &Default::default(), edition, None);
             let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
 
             // These characters don't need to be escaped in a URI.
-            // FIXME: use a library function for percent encoding.
+            // See https://url.spec.whatwg.org/#query-percent-encode-set
+            // and https://url.spec.whatwg.org/#urlencoded-parsing
+            // and https://url.spec.whatwg.org/#url-code-points
             fn dont_escape(c: u8) -> bool {
                 (b'a' <= c && c <= b'z')
                     || (b'A' <= c && c <= b'Z')
@@ -304,17 +305,32 @@ fn dont_escape(c: u8) -> bool {
                     || c == b'-'
                     || c == b'_'
                     || c == b'.'
+                    || c == b','
                     || c == b'~'
                     || c == b'!'
                     || c == b'\''
                     || c == b'('
                     || c == b')'
                     || c == b'*'
+                    || c == b'/'
+                    || c == b';'
+                    || c == b':'
+                    || c == b'?'
+                    // As described in urlencoded-parsing, the
+                    // first `=` is the one that separates key from
+                    // value. Following `=`s are part of the value.
+                    || c == b'='
             }
             let mut test_escaped = String::new();
             for b in test.bytes() {
                 if dont_escape(b) {
                     test_escaped.push(char::from(b));
+                } else if b == b' ' {
+                    // URL queries are decoded with + replaced with SP
+                    test_escaped.push('+');
+                } else if b == b'%' {
+                    test_escaped.push('%');
+                    test_escaped.push('%');
                 } else {
                     write!(test_escaped, "%{:02X}", b).unwrap();
                 }
@@ -784,45 +800,26 @@ pub(crate) fn find_testable_code<T: doctest::Tester>(
 }
 
 pub(crate) struct ExtraInfo<'tcx> {
-    id: ExtraInfoId,
+    def_id: DefId,
     sp: Span,
     tcx: TyCtxt<'tcx>,
 }
 
-enum ExtraInfoId {
-    Hir(HirId),
-    Def(DefId),
-}
-
 impl<'tcx> ExtraInfo<'tcx> {
-    pub(crate) fn new(tcx: TyCtxt<'tcx>, hir_id: HirId, sp: Span) -> ExtraInfo<'tcx> {
-        ExtraInfo { id: ExtraInfoId::Hir(hir_id), sp, tcx }
-    }
-
-    pub(crate) fn new_did(tcx: TyCtxt<'tcx>, did: DefId, sp: Span) -> ExtraInfo<'tcx> {
-        ExtraInfo { id: ExtraInfoId::Def(did), sp, tcx }
+    pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: DefId, sp: Span) -> ExtraInfo<'tcx> {
+        ExtraInfo { def_id, sp, tcx }
     }
 
     fn error_invalid_codeblock_attr(&self, msg: &str, help: &str) {
-        let hir_id = match self.id {
-            ExtraInfoId::Hir(hir_id) => hir_id,
-            ExtraInfoId::Def(item_did) => {
-                match item_did.as_local() {
-                    Some(item_did) => self.tcx.hir().local_def_id_to_hir_id(item_did),
-                    None => {
-                        // If non-local, no need to check anything.
-                        return;
-                    }
-                }
-            }
-        };
-        self.tcx.struct_span_lint_hir(
-            crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
-            hir_id,
-            self.sp,
-            msg,
-            |lint| lint.help(help),
-        );
+        if let Some(def_id) = self.def_id.as_local() {
+            self.tcx.struct_span_lint_hir(
+                crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
+                self.tcx.hir().local_def_id_to_hir_id(def_id),
+                self.sp,
+                msg,
+                |lint| lint.help(help),
+            );
+        }
     }
 }
 
@@ -1191,18 +1188,18 @@ fn markdown_summary_with_limit(
             Event::Start(tag) => match tag {
                 Tag::Emphasis => buf.open_tag("em"),
                 Tag::Strong => buf.open_tag("strong"),
-                Tag::CodeBlock(..) => return ControlFlow::BREAK,
+                Tag::CodeBlock(..) => return ControlFlow::Break(()),
                 _ => {}
             },
             Event::End(tag) => match tag {
                 Tag::Emphasis | Tag::Strong => buf.close_tag(),
-                Tag::Paragraph | Tag::Heading(..) => return ControlFlow::BREAK,
+                Tag::Paragraph | Tag::Heading(..) => return ControlFlow::Break(()),
                 _ => {}
             },
             Event::HardBreak | Event::SoftBreak => buf.push(" ")?,
             _ => {}
         };
-        ControlFlow::CONTINUE
+        ControlFlow::Continue(())
     });
 
     (buf.finish(), stopped_early)
index 20b51336c350f9300aa9f28859f6a17a01e87003..15258a467a228106abf2a18d728c066681b2bc6a 100644 (file)
@@ -6,7 +6,7 @@
 use std::sync::mpsc::{channel, Receiver};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
@@ -56,7 +56,7 @@ pub(crate) struct Context<'tcx> {
     pub(super) render_redirect_pages: bool,
     /// Tracks section IDs for `Deref` targets so they match in both the main
     /// body and the sidebar.
-    pub(super) deref_id_map: FxHashMap<DefId, String>,
+    pub(super) deref_id_map: DefIdMap<String>,
     /// The map used to ensure all generated 'id=' attributes are unique.
     pub(super) id_map: IdMap,
     /// Shared mutable state.
@@ -464,8 +464,7 @@ fn init(
         // If user passed in `--playground-url` arg, we fill in crate name here
         let mut playground = None;
         if let Some(url) = playground_url {
-            playground =
-                Some(markdown::Playground { crate_name: Some(krate.name(tcx).to_string()), url });
+            playground = Some(markdown::Playground { crate_name: Some(krate.name(tcx)), url });
         }
         let mut layout = layout::Layout {
             logo: String::new(),
@@ -491,7 +490,7 @@ fn init(
                 }
                 (sym::html_playground_url, Some(s)) => {
                     playground = Some(markdown::Playground {
-                        crate_name: Some(krate.name(tcx).to_string()),
+                        crate_name: Some(krate.name(tcx)),
                         url: s.to_string(),
                     });
                 }
@@ -545,7 +544,7 @@ fn init(
             dst,
             render_redirect_pages: false,
             id_map,
-            deref_id_map: FxHashMap::default(),
+            deref_id_map: Default::default(),
             shared: Rc::new(scx),
             include_sources,
             types_with_notable_traits: FxHashSet::default(),
@@ -573,7 +572,7 @@ fn make_child_renderer(&self) -> Self {
             current: self.current.clone(),
             dst: self.dst.clone(),
             render_redirect_pages: self.render_redirect_pages,
-            deref_id_map: FxHashMap::default(),
+            deref_id_map: Default::default(),
             id_map: IdMap::new(),
             shared: Rc::clone(&self.shared),
             include_sources: self.include_sources,
index 358b9185fb36126997dbb2af23f78d4eb7cebb67..be6de231854ba1198b32710da0bc41467dbeb6e7 100644 (file)
@@ -50,7 +50,7 @@
 use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def::CtorKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_hir::Mutability;
 use rustc_middle::middle::stability;
 use rustc_middle::ty;
@@ -100,7 +100,7 @@ pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
 #[derive(Debug)]
 pub(crate) struct IndexItem {
     pub(crate) ty: ItemType,
-    pub(crate) name: String,
+    pub(crate) name: Symbol,
     pub(crate) path: String,
     pub(crate) desc: String,
     pub(crate) parent: Option<DefId>,
@@ -1115,7 +1115,7 @@ fn render_assoc_items(
     it: DefId,
     what: AssocItemRender<'_>,
 ) {
-    let mut derefs = FxHashSet::default();
+    let mut derefs = DefIdSet::default();
     derefs.insert(it);
     render_assoc_items_inner(w, cx, containing_item, it, what, &mut derefs)
 }
@@ -1126,7 +1126,7 @@ fn render_assoc_items_inner(
     containing_item: &clean::Item,
     it: DefId,
     what: AssocItemRender<'_>,
-    derefs: &mut FxHashSet<DefId>,
+    derefs: &mut DefIdSet,
 ) {
     info!("Documenting associated items of {:?}", containing_item.name);
     let shared = Rc::clone(&cx.shared);
@@ -1215,7 +1215,7 @@ fn render_deref_methods(
     impl_: &Impl,
     container_item: &clean::Item,
     deref_mut: bool,
-    derefs: &mut FxHashSet<DefId>,
+    derefs: &mut DefIdSet,
 ) {
     let cache = cx.cache();
     let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
@@ -1343,7 +1343,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
                     write!(
                         &mut out,
                         "<h3>Notable traits for <code>{}</code></h3>\
-                     <pre class=\"content\"><code>",
+                     <pre><code>",
                         impl_.for_.print(cx)
                     );
                 }
@@ -1528,11 +1528,7 @@ fn doc_impl_item(
                             })
                         })
                         .map(|item| format!("{}.{}", item.type_(), name));
-                    write!(
-                        w,
-                        "<section id=\"{}\" class=\"{}{} has-srclink\">",
-                        id, item_type, in_trait_class,
-                    );
+                    write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
                     render_rightside(w, cx, item, containing_item, render_mode);
                     if trait_.is_some() {
                         // Anchors are only used on trait impls.
@@ -1554,11 +1550,7 @@ fn doc_impl_item(
             kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(
-                    w,
-                    "<section id=\"{}\" class=\"{}{} has-srclink\">",
-                    id, item_type, in_trait_class
-                );
+                write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
                 render_rightside(w, cx, item, containing_item, render_mode);
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
@@ -1606,11 +1598,7 @@ fn doc_impl_item(
             clean::AssocTypeItem(tydef, _bounds) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(
-                    w,
-                    "<section id=\"{}\" class=\"{}{} has-srclink\">",
-                    id, item_type, in_trait_class
-                );
+                write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
                     write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
@@ -1844,7 +1832,7 @@ pub(crate) fn render_impl_summary(
     } else {
         format!(" data-aliases=\"{}\"", aliases.join(","))
     };
-    write!(w, "<section id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
+    write!(w, "<section id=\"{}\" class=\"impl\"{}>", id, aliases);
     render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
     write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
     write!(w, "<h3 class=\"code-header\">");
@@ -2175,7 +2163,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
             if let Some(impl_) =
                 v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait())
             {
-                let mut derefs = FxHashSet::default();
+                let mut derefs = DefIdSet::default();
                 derefs.insert(did);
                 sidebar_deref_methods(cx, out, impl_, v, &mut derefs, &mut used_links);
             }
@@ -2195,7 +2183,7 @@ fn sidebar_deref_methods(
     out: &mut Buffer,
     impl_: &Impl,
     v: &[Impl],
-    derefs: &mut FxHashSet<DefId>,
+    derefs: &mut DefIdSet,
     used_links: &mut FxHashSet<String>,
 ) {
     let c = cx.cache();
@@ -2769,8 +2757,8 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
     let mut work = VecDeque::new();
 
     let mut process_path = |did: DefId| {
-        let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone());
-        let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
+        let get_extern = || cache.external_paths.get(&did).map(|s| &s.0);
+        let fqp = cache.exact_paths.get(&did).or_else(get_extern);
 
         if let Some(path) = fqp {
             out.push(join_with_double_colon(&path));
@@ -2921,7 +2909,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
         // Look for the example file in the source map if it exists, otherwise return a dummy span
         let file_span = (|| {
             let source_map = tcx.sess.source_map();
-            let crate_src = tcx.sess.local_crate_source_file.as_ref()?;
+            let crate_src = tcx.sess.local_crate_source_file()?;
             let abs_crate_src = crate_src.canonicalize().ok()?;
             let crate_root = abs_crate_src.parent()?.parent()?;
             let rel_path = path.strip_prefix(crate_root).ok()?;
index d6e57decdcf18463cb76d372d4f688484c3bbff6..b0288d55c256ad84e90c04ab8bc3eb9ff992092b 100644 (file)
@@ -391,7 +391,7 @@ fn cmp(
                 };
                 write!(
                     w,
-                    "<div class=\"item-left {stab}{add}import-item\"{id}>\
+                    "<div class=\"item-left{add}{stab}\"{id}>\
                          <code>{vis}{imp}</code>\
                      </div>\
                      {stab_tags_before}{stab_tags}{stab_tags_after}",
@@ -437,7 +437,7 @@ fn cmp(
                 };
                 write!(
                     w,
-                    "<div class=\"item-left {stab}{add}module-item\">\
+                    "<div class=\"item-left{add}{stab}\">\
                         <a class=\"{class}\" href=\"{href}\" title=\"{title}\">{name}</a>\
                         {visibility_emoji}\
                         {unsafety_flag}\
@@ -452,7 +452,7 @@ fn cmp(
                     stab = stab.unwrap_or_default(),
                     unsafety_flag = unsafety_flag,
                     href = item_path(myitem.type_(), myitem.name.unwrap().as_str()),
-                    title = [full_path(cx, myitem), myitem.type_().to_string()]
+                    title = [myitem.type_().to_string(), full_path(cx, myitem)]
                         .iter()
                         .filter_map(|s| if !s.is_empty() { Some(s.as_str()) } else { None })
                         .collect::<Vec<_>>()
@@ -531,7 +531,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
         f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx));
 
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "fn", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             w.reserve(header_len);
             write!(
@@ -570,7 +570,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
 
     // Output the trait definition
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "trait", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             write!(
                 w,
@@ -735,7 +735,7 @@ fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::
             let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
             write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
         }
-        write!(w, "<section id=\"{}\" class=\"method has-srclink\">", id);
+        write!(w, "<section id=\"{}\" class=\"method\">", id);
         render_rightside(w, cx, m, t, RenderMode::Normal);
         write!(w, "<h4 class=\"code-header\">");
         render_assoc_item(
@@ -1027,8 +1027,8 @@ fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::
         .chain(std::iter::once("implementors"))
         .collect();
     if let Some(did) = it.item_id.as_def_id() &&
-        let get_extern = { || cache.external_paths.get(&did).map(|s| s.0.clone()) } &&
-        let Some(fqp) = cache.exact_paths.get(&did).cloned().or_else(get_extern) {
+        let get_extern = { || cache.external_paths.get(&did).map(|s| &s.0) } &&
+        let Some(fqp) = cache.exact_paths.get(&did).or_else(get_extern) {
         js_src_path.extend(fqp[..fqp.len() - 1].iter().copied());
         js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), fqp.last().unwrap()));
     } else {
@@ -1051,7 +1051,7 @@ fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::
 
 fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::TraitAlias) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "trait-alias", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             write!(
                 w,
@@ -1075,7 +1075,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &
 
 fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "opaque", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             write!(
                 w,
@@ -1099,7 +1099,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &cl
 
 fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Typedef) {
     fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
-        wrap_item(w, "typedef", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             write!(w, "{}", visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx));
             write!(
@@ -1128,7 +1128,7 @@ fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::
 
 fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Union) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "union", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             render_union(w, it, Some(&s.generics), &s.fields, "", cx);
         });
@@ -1193,7 +1193,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
     let tcx = cx.tcx();
     let count_variants = e.variants().count();
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "enum", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_pre(w, it, "");
             write!(
                 w,
@@ -1357,17 +1357,17 @@ fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &c
         let name = it.name.expect("proc-macros always have names");
         match m.kind {
             MacroKind::Bang => {
-                wrap_item(w, "macro", |w| {
+                wrap_item(w, |w| {
                     write!(w, "{}!() {{ /* proc-macro */ }}", name);
                 });
             }
             MacroKind::Attr => {
-                wrap_item(w, "attr", |w| {
+                wrap_item(w, |w| {
                     write!(w, "#[{}]", name);
                 });
             }
             MacroKind::Derive => {
-                wrap_item(w, "derive", |w| {
+                wrap_item(w, |w| {
                     write!(w, "#[derive({})]", name);
                     if !m.helpers.is_empty() {
                         w.push_str("\n{\n");
@@ -1401,7 +1401,7 @@ fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
 
 fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "const", |w| {
+        wrap_item(w, |w| {
             let tcx = cx.tcx();
             render_attributes_in_code(w, it);
 
@@ -1451,7 +1451,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
 
 fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "struct", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_code(w, it);
             render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
         });
@@ -1504,7 +1504,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
 
 fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "static", |w| {
+        wrap_item(w, |w| {
             render_attributes_in_code(w, it);
             write!(
                 w,
@@ -1521,7 +1521,7 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
 
 fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
     wrap_into_item_decl(w, |w| {
-        wrap_item(w, "foreigntype", |w| {
+        wrap_item(w, |w| {
             w.write_str("extern {\n");
             render_attributes_in_code(w, it);
             write!(
@@ -1618,11 +1618,11 @@ fn wrap_into_item_decl<F>(w: &mut Buffer, f: F)
     w.write_str("</div>")
 }
 
-fn wrap_item<F>(w: &mut Buffer, item_name: &str, f: F)
+fn wrap_item<F>(w: &mut Buffer, f: F)
 where
     F: FnOnce(&mut Buffer),
 {
-    w.write_fmt(format_args!("<pre class=\"rust {}\"><code>", item_name));
+    w.write_str(r#"<pre class="rust"><code>"#);
     f(w);
     w.write_str("</code></pre>");
 }
index bc74d9cf969741eb56e3ba7cb91c007ab2900ea3..5b0caac099bc3010c7cb9873dc7a8dba990e3d80 100644 (file)
@@ -29,13 +29,13 @@ pub(crate) fn build_index<'tcx>(
     // Attach all orphan items to the type's definition if the type
     // has since been learned.
     for &OrphanImplItem { parent, ref item, ref impl_generics } in &cache.orphan_impl_items {
-        if let Some(&(ref fqp, _)) = cache.paths.get(&parent) {
+        if let Some((fqp, _)) = cache.paths.get(&parent) {
             let desc = item
                 .doc_value()
                 .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache)));
             cache.search_index.push(IndexItem {
                 ty: item.type_(),
-                name: item.name.unwrap().to_string(),
+                name: item.name.unwrap(),
                 path: join_with_double_colon(&fqp[..fqp.len() - 1]),
                 desc,
                 parent: Some(parent),
@@ -58,8 +58,8 @@ pub(crate) fn build_index<'tcx>(
     // Sort search index items. This improves the compressibility of the search index.
     cache.search_index.sort_unstable_by(|k1, k2| {
         // `sort_unstable_by_key` produces lifetime errors
-        let k1 = (&k1.path, &k1.name, &k1.ty, &k1.parent);
-        let k2 = (&k2.path, &k2.name, &k2.ty, &k2.parent);
+        let k1 = (&k1.path, k1.name.as_str(), &k1.ty, &k1.parent);
+        let k2 = (&k2.path, k2.name.as_str(), &k2.ty, &k2.parent);
         std::cmp::Ord::cmp(&k1, &k2)
     });
 
@@ -240,7 +240,7 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             )?;
             crate_data.serialize_field(
                 "n",
-                &self.items.iter().map(|item| &item.name).collect::<Vec<_>>(),
+                &self.items.iter().map(|item| item.name.as_str()).collect::<Vec<_>>(),
             )?;
             crate_data.serialize_field(
                 "q",
@@ -299,7 +299,7 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             )?;
             crate_data.serialize_field(
                 "p",
-                &self.paths.iter().map(|(it, s)| (it, s.to_string())).collect::<Vec<_>>(),
+                &self.paths.iter().map(|(it, s)| (it, s.as_str())).collect::<Vec<_>>(),
             )?;
             if has_aliases {
                 crate_data.serialize_field("a", &self.aliases)?;
@@ -573,7 +573,7 @@ fn get_fn_inputs_and_outputs<'tcx>(
     let decl = &func.decl;
 
     let combined_generics;
-    let (self_, generics) = if let Some(&(ref impl_self, ref impl_generics)) = impl_generics {
+    let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_generics {
         match (impl_generics.is_empty(), func.generics.is_empty()) {
             (true, _) => (Some(impl_self), &func.generics),
             (_, true) => (Some(impl_self), impl_generics),
index ca3e9916487aad060546b9ac358d9f3a7fb20515..bc8badad38eb0578ea3a0b5f40310241b66eab0c 100644 (file)
@@ -138,7 +138,7 @@ fn collect(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> {
         Ok((ret, krates))
     }
 
-    /// Read a file and return all lines that match the <code>"{crate}":{data},\ </code> format,
+    /// Read a file and return all lines that match the <code>"{crate}":{data},\</code> format,
     /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`.
     ///
     /// This forms the payload of files that look like this:
index 2070bb54b1ba9bcc8e0777a96245487545851d17..8699508e43916af754f142937b60ac7312714c8b 100644 (file)
@@ -497,7 +497,7 @@ ul.block, .block li {
        padding-left: 24px;
 }
 
-.sidebar a, .sidebar .current {
+.sidebar a {
        color: var(--sidebar-link-color);
 }
 .sidebar .current,
@@ -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,
@@ -977,8 +977,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
                0 -1px 0 black;
 }
 
-.module-item.unstable,
-.import-item.unstable {
+.item-left.unstable {
        opacity: 0.65;
 }
 
@@ -1214,11 +1213,11 @@ a.test-arrow:hover {
        content: "\00a0";
 }
 
-.notable .docblock {
+.notable .content {
        margin: 0.25em 0.5em;
 }
 
-.notable .docblock pre, .notable .docblock code {
+.notable .content pre, .notable .content code {
        background: transparent;
        margin: 0;
        padding: 0;
@@ -1226,6 +1225,10 @@ a.test-arrow:hover {
        white-space: pre-wrap;
 }
 
+.notable .content > h3:first-child {
+       margin: 0 0 5px 0;
+}
+
 .search-failed {
        text-align: center;
        margin-top: 20px;
@@ -1893,19 +1896,25 @@ in storage.js
        right: 0.25em;
 }
 
-.scraped-example:not(.expanded) .code-wrapper:before,
-.scraped-example:not(.expanded) .code-wrapper:after {
+.scraped-example:not(.expanded) .code-wrapper::before,
+.scraped-example:not(.expanded) .code-wrapper::after {
        content: " ";
        width: 100%;
        height: 5px;
        position: absolute;
        z-index: 1;
 }
-.scraped-example:not(.expanded) .code-wrapper:before {
+.scraped-example:not(.expanded) .code-wrapper::before {
        top: 0;
+       background: linear-gradient(to bottom,
+               var(--scrape-example-code-wrapper-background-start),
+               var(--scrape-example-code-wrapper-background-end));
 }
-.scraped-example:not(.expanded) .code-wrapper:after {
+.scraped-example:not(.expanded) .code-wrapper::after {
        bottom: 0;
+       background: linear-gradient(to top,
+               var(--scrape-example-code-wrapper-background-start),
+               var(--scrape-example-code-wrapper-background-end));
 }
 
 .scraped-example .code-wrapper .example-wrap {
index 91419093147d728bbdda9478eecda9305db4621e..c28cefebc8bf5fccf3796a295959267f6a945810 100644 (file)
@@ -1,15 +1,9 @@
 .setting-line {
-       margin: 0.6em 0 0.6em 0.3em;
+       margin: 1.2em 0.6em;
        position: relative;
 }
 
-.setting-line .choices {
-       display: flex;
-       flex-wrap: wrap;
-}
-
-.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 .setting-name {
-       width: 100%;
-}
-
-.radio-line .choice {
+.setting-radio {
        margin-top: 0.1em;
        margin-bottom: 0.1em;
        min-width: 3.8em;
        padding: 0.3em;
-       display: flex;
+       display: inline-flex;
        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;
 }
 
-#settings .setting-line {
-       margin: 1.2em 0.6em;
-}
-
-.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 979e7e0f999eda96a2d18ab552c3b668076d8965..ed779bf6166eed34cb97036796868426617b05aa 100644 (file)
@@ -97,6 +97,8 @@ Original by Dempfi (https://github.com/dempfi/ayu)
        --scrape-example-help-color: #eee;
        --scrape-example-help-hover-border-color: #fff;
        --scrape-example-help-hover-color: #fff;
+       --scrape-example-code-wrapper-background-start: rgba(15, 20, 25, 1);
+       --scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0);
 }
 
 h1, h2, h3, h4 {
@@ -203,10 +205,3 @@ above the `@media (max-width: 700px)` rules due to a bug in the css checker */
 #source-sidebar div.files > a.selected {
        color: #ffb44c;
 }
-
-.scraped-example:not(.expanded) .code-wrapper::before {
-       background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
-}
-.scraped-example:not(.expanded) .code-wrapper::after {
-       background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
-}
index fb15863b027ca5f992954da7656696bc8dec4fb3..3766f0daa42ff837264542bee9f59c15212b3170 100644 (file)
@@ -92,6 +92,8 @@
        --scrape-example-help-color: #eee;
        --scrape-example-help-hover-border-color: #fff;
        --scrape-example-help-hover-color: #fff;
+       --scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
+       --scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
 }
 
 #search-tabs > button:not(.selected) {
        border-top-color: #0089ff;
        background-color: #353535;
 }
-
-.scraped-example:not(.expanded) .code-wrapper::before {
-       background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
-}
-.scraped-example:not(.expanded) .code-wrapper::after {
-       background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
-}
index 053fa78d1dc5884dae832d7524e8c3654b3e0828..8a7f6abcf8d8e83141923f3a8400bd38606725bd 100644 (file)
@@ -89,6 +89,8 @@
        --scrape-example-help-color: #333;
        --scrape-example-help-hover-border-color: #000;
        --scrape-example-help-hover-color: #000;
+       --scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
+       --scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
 }
 
 #search-tabs > button:not(.selected) {
        background-color: #ffffff;
        border-top-color: #0089ff;
 }
-
-.scraped-example:not(.expanded) .code-wrapper::before {
-       background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
-}
-.scraped-example:not(.expanded) .code-wrapper::after {
-       background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
-}
index 4f6f8c57597f08408822da9a9a8f4a78dd1f7302..b9ad8ef70e917af855f4857ed46fbc40c5056194 100644 (file)
@@ -390,7 +390,8 @@ function loadCss(cssUrl) {
         }
 
         if (document.activeElement.tagName === "INPUT" &&
-            document.activeElement.type !== "checkbox") {
+            document.activeElement.type !== "checkbox" &&
+            document.activeElement.type !== "radio") {
             switch (getVirtualKey(ev)) {
             case "Escape":
                 handleEscape(ev);
@@ -803,15 +804,10 @@ function loadCss(cssUrl) {
         }
     });
 
-    function handleClick(id, f) {
-        const elem = document.getElementById(id);
-        if (elem) {
-            elem.addEventListener("click", f);
-        }
+    const mainElem = document.getElementById(MAIN_ID);
+    if (mainElem) {
+        mainElem.addEventListener("click", hideSidebar);
     }
-    handleClick(MAIN_ID, () => {
-        hideSidebar();
-    });
 
     onEachLazy(document.querySelectorAll("a[href^='#']"), el => {
         // For clicks on internal links (<A> tags with a hash property), we expand the section we're
@@ -847,7 +843,7 @@ function loadCss(cssUrl) {
         window.hideAllModals(false);
         const ty = e.getAttribute("data-ty");
         const wrapper = document.createElement("div");
-        wrapper.innerHTML = "<div class=\"docblock\">" + window.NOTABLE_TRAITS[ty] + "</div>";
+        wrapper.innerHTML = "<div class=\"content\">" + window.NOTABLE_TRAITS[ty] + "</div>";
         wrapper.className = "notable popover";
         const focusCatcher = document.createElement("div");
         focusCatcher.setAttribute("tabindex", "0");
@@ -945,7 +941,7 @@ function loadCss(cssUrl) {
                 return;
             }
             if (!this.NOTABLE_FORCE_VISIBLE &&
-                !elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) {
+                !elemIsInParent(ev.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) {
                 hideNotable(true);
             }
         };
@@ -1087,6 +1083,9 @@ function loadCss(cssUrl) {
      * Show the help popup menu.
      */
     function showHelp() {
+        // Prevent `blur` events from being dispatched as a result of closing
+        // other modals.
+        getHelpButton().querySelector("a").focus();
         const menu = getHelpMenu(true);
         if (menu.style.display === "none") {
             window.hideAllModals();
@@ -1143,7 +1142,11 @@ function loadCss(cssUrl) {
 (function() {
     let reset_button_timeout = null;
 
-    window.copy_path = but => {
+    const but = document.getElementById("copy-path");
+    if (!but) {
+        return;
+    }
+    but.onclick = () => {
         const parent = but.parentElement;
         const path = [];
 
index 1b8822b0b2b7dedfa0f4c6589043a1208e799d53..88592fa0c84c1453fbda216b9f3d92eddb0ab307 100644 (file)
@@ -781,7 +781,29 @@ function initSearch(rawSearchIndex) {
                     return a - b;
                 }
 
-                // Sort by non levenshtein results and then levenshtein results by the distance
+                // sort by index of keyword in item name (no literal occurrence goes later)
+                a = (aaa.index < 0);
+                b = (bbb.index < 0);
+                if (a !== b) {
+                    return a - b;
+                }
+
+                // Sort by distance in the path part, if specified
+                // (less changes required to match means higher rankings)
+                a = aaa.path_lev;
+                b = bbb.path_lev;
+                if (a !== b) {
+                    return a - b;
+                }
+
+                // (later literal occurrence, if any, goes later)
+                a = aaa.index;
+                b = bbb.index;
+                if (a !== b) {
+                    return a - b;
+                }
+
+                // Sort by distance in the name part, the last part of the path
                 // (less changes required to match means higher rankings)
                 a = (aaa.lev);
                 b = (bbb.lev);
@@ -810,19 +832,6 @@ function initSearch(rawSearchIndex) {
                     return (a > b ? +1 : -1);
                 }
 
-                // sort by index of keyword in item name (no literal occurrence goes later)
-                a = (aaa.index < 0);
-                b = (bbb.index < 0);
-                if (a !== b) {
-                    return a - b;
-                }
-                // (later literal occurrence, if any, goes later)
-                a = aaa.index;
-                b = bbb.index;
-                if (a !== b) {
-                    return a - b;
-                }
-
                 // special precedence for primitive and keyword pages
                 if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) ||
                     (aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) {
@@ -1230,15 +1239,19 @@ function initSearch(rawSearchIndex) {
          * * `id` is the index in both `searchWords` and `searchIndex` arrays for this element.
          * * `index` is an `integer`` used to sort by the position of the word in the item's name.
          * * `lev` is the main metric used to sort the search results.
+         * * `path_lev` is zero if a single-component search query is used, otherwise it's the
+         *   distance computed for everything other than the last path component.
          *
          * @param {Results} results
          * @param {string} fullId
          * @param {integer} id
          * @param {integer} index
          * @param {integer} lev
+         * @param {integer} path_lev
          */
-        function addIntoResults(results, fullId, id, index, lev) {
-            if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) {
+        function addIntoResults(results, fullId, id, index, lev, path_lev) {
+            const inBounds = lev <= MAX_LEV_DISTANCE || index !== -1;
+            if (lev === 0 || (!parsedQuery.literalSearch && inBounds)) {
                 if (results[fullId] !== undefined) {
                     const result = results[fullId];
                     if (result.dontValidate || result.lev <= lev) {
@@ -1250,6 +1263,7 @@ function initSearch(rawSearchIndex) {
                     index: index,
                     dontValidate: parsedQuery.literalSearch,
                     lev: lev,
+                    path_lev: path_lev,
                 };
             }
         }
@@ -1280,68 +1294,68 @@ function initSearch(rawSearchIndex) {
             if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
                 return;
             }
-            let lev, lev_add = 0, index = -1;
+            let lev, index = -1, path_lev = 0;
             const fullId = row.id;
+            const searchWord = searchWords[pos];
 
             const in_args = findArg(row, elem, parsedQuery.typeFilter);
             const returned = checkReturned(row, elem, parsedQuery.typeFilter);
 
-            addIntoResults(results_in_args, fullId, pos, index, in_args);
-            addIntoResults(results_returned, fullId, pos, index, returned);
+            // path_lev is 0 because no parent path information is currently stored
+            // in the search index
+            addIntoResults(results_in_args, fullId, pos, -1, in_args, 0);
+            addIntoResults(results_returned, fullId, pos, -1, returned, 0);
 
             if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
                 return;
             }
-            const searchWord = searchWords[pos];
 
-            if (parsedQuery.literalSearch) {
-                if (searchWord === elem.name) {
-                    addIntoResults(results_others, fullId, pos, -1, 0);
-                }
-                return;
+            const row_index = row.normalizedName.indexOf(elem.pathLast);
+            const word_index = searchWord.indexOf(elem.pathLast);
+
+            // lower indexes are "better" matches
+            // rank based on the "best" match
+            if (row_index === -1) {
+                index = word_index;
+            } else if (word_index === -1) {
+                index = row_index;
+            } else if (word_index < row_index) {
+                index = word_index;
+            } else {
+                index = row_index;
             }
 
             // No need to check anything else if it's a "pure" generics search.
             if (elem.name.length === 0) {
                 if (row.type !== null) {
                     lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1);
-                    addIntoResults(results_others, fullId, pos, index, lev);
+                    // path_lev is 0 because we know it's empty
+                    addIntoResults(results_others, fullId, pos, index, lev, 0);
                 }
                 return;
             }
 
             if (elem.fullPath.length > 1) {
-                lev = checkPath(elem.pathWithoutLast, row);
-                if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) {
+                path_lev = checkPath(elem.pathWithoutLast, row);
+                if (path_lev > MAX_LEV_DISTANCE) {
                     return;
-                } else if (lev > 0) {
-                    lev_add = lev / 10;
                 }
             }
 
-            if (searchWord.indexOf(elem.pathLast) > -1 ||
-                row.normalizedName.indexOf(elem.pathLast) > -1
-            ) {
-                index = row.normalizedName.indexOf(elem.pathLast);
-            }
-            lev = levenshtein(searchWord, elem.pathLast);
-            if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) {
-                if (elem.pathLast.length < 6) {
-                    lev = 1;
-                } else {
-                    lev = 0;
+            if (parsedQuery.literalSearch) {
+                if (searchWord === elem.name) {
+                    addIntoResults(results_others, fullId, pos, index, 0, path_lev);
                 }
-            }
-            lev += lev_add;
-            if (lev > MAX_LEV_DISTANCE) {
                 return;
-            } else if (index !== -1 && elem.fullPath.length < 2) {
-                lev -= 1;
             }
-            if (lev < 0) {
-                lev = 0;
+
+            lev = levenshtein(searchWord, elem.pathLast);
+
+            if (index === -1 && lev + path_lev > MAX_LEV_DISTANCE) {
+                return;
             }
-            addIntoResults(results_others, fullId, pos, index, lev);
+
+            addIntoResults(results_others, fullId, pos, index, lev, path_lev);
         }
 
         /**
@@ -1386,7 +1400,7 @@ function initSearch(rawSearchIndex) {
                 return;
             }
             const lev = Math.round(totalLev / nbLev);
-            addIntoResults(results, row.id, pos, 0, lev);
+            addIntoResults(results, row.id, pos, 0, lev, 0);
         }
 
         function innerRunQuery() {
index 9ed8f63610ff6b336d940e934043a6a7f53dd540..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}">
-    <span class="setting-name">${setting_name}</span>
-<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 ee2880bf6d195e23a91bedf640a667c29052cbc3..3a1867b7feba3eda5980b0b3d8235fe59c8ab234 100644 (file)
@@ -6,7 +6,7 @@
         <a href="{{component.path|safe}}index.html">{{component.name}}</a>::<wbr>
         {%- endfor -%}
         <a class="{{item_type}}" href="#">{{name}}</a> {#- -#}
-        <button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"> {#- -#}
+        <button id="copy-path" title="Copy item path to clipboard"> {#- -#}
         <img src="{{static_root_path|safe}}{{clipboard_svg}}" {# -#}
                 width="19" height="18" {# -#}
                 alt="Copy item path"> {#- -#}
index c5c687df74fd88072f0f348134f219b19b96af8d..982370aa21c43b2ef4960f73714b2993710e2748 100644 (file)
@@ -1,5 +1,4 @@
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::DefIdSet;
 
 use crate::{
     clean::{self, Import, ImportSource, Item},
 /// See [#100973](https://github.com/rust-lang/rust/issues/100973) and
 /// [#101103](https://github.com/rust-lang/rust/issues/101103) for times when
 /// this information is needed.
-pub(crate) fn get_imports(krate: clean::Crate) -> (clean::Crate, FxHashSet<DefId>) {
-    let mut finder = ImportFinder { imported: FxHashSet::default() };
+pub(crate) fn get_imports(krate: clean::Crate) -> (clean::Crate, DefIdSet) {
+    let mut finder = ImportFinder::default();
     let krate = finder.fold_crate(krate);
     (krate, finder.imported)
 }
 
+#[derive(Default)]
 struct ImportFinder {
-    imported: FxHashSet<DefId>,
+    imported: DefIdSet,
 }
 
 impl DocFolder for ImportFinder {
index 1196f944faad2d26981b806023fe739cfaacc953..5adc0d2a40e41bf2944e0aa079c169decf4fb253 100644 (file)
@@ -13,8 +13,8 @@
 use std::path::PathBuf;
 use std::rc::Rc;
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::DefId;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::def_id::LOCAL_CRATE;
@@ -40,7 +40,7 @@ pub(crate) struct JsonRenderer<'tcx> {
     /// The directory where the blob will be written to.
     out_path: PathBuf,
     cache: Rc<Cache>,
-    imported_items: FxHashSet<DefId>,
+    imported_items: DefIdSet,
 }
 
 impl<'tcx> JsonRenderer<'tcx> {
index 86454e1f2eb7316d239d4544c3adeec49e917e89..64108c882851838286923356613f93490bf5e7a2 100644 (file)
@@ -6,7 +6,6 @@
 #![feature(array_methods)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(drain_filter)]
 #![feature(is_terminal)]
 #![feature(let_chains)]
@@ -815,7 +814,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 02b22789608691fed717a4f8cfc59a37a79a0a22..0b22f943dab99db214553c2696f25beeacc8b0c0 100644 (file)
@@ -216,13 +216,7 @@ fn visit_item(&mut self, i: &clean::Item) {
                 );
 
                 let has_doc_example = tests.found_tests != 0;
-                // The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
-                // would presumably panic if a fake `DefIndex` were passed.
-                let hir_id = self
-                    .ctx
-                    .tcx
-                    .hir()
-                    .local_def_id_to_hir_id(i.item_id.expect_def_id().expect_local());
+                let hir_id = DocContext::as_local_hir_id(self.ctx.tcx, i.item_id).unwrap();
                 let (level, source) = self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id);
 
                 // In case we have:
index 6aa2dda980cf31a14a41f014c76805a3c7692eeb..f3961d5017ef4b99c80b7831446733a60c0c1648 100644 (file)
@@ -14,8 +14,8 @@
 use crate::visit_ast::inherits_doc_hidden;
 use rustc_hir as hir;
 use rustc_middle::lint::LintLevelSource;
+use rustc_middle::ty::DefIdTree;
 use rustc_session::lint;
-use rustc_span::symbol::sym;
 
 pub(crate) const CHECK_DOC_TEST_VISIBILITY: Pass = Pass {
     name: "check_doc_test_visibility",
@@ -79,11 +79,11 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
 
     // The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
     // would presumably panic if a fake `DefIndex` were passed.
-    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.item_id.expect_def_id().expect_local());
+    let def_id = item.item_id.expect_def_id().expect_local();
 
     // check if parent is trait impl
-    if let Some(parent_hir_id) = cx.tcx.hir().opt_parent_id(hir_id) {
-        if let Some(parent_node) = cx.tcx.hir().find(parent_hir_id) {
+    if let Some(parent_def_id) = cx.tcx.opt_local_parent(def_id) {
+        if let Some(parent_node) = cx.tcx.hir().find_by_def_id(parent_def_id) {
             if matches!(
                 parent_node,
                 hir::Node::Item(hir::Item {
@@ -96,13 +96,16 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
         }
     }
 
-    if cx.tcx.hir().attrs(hir_id).lists(sym::doc).has_word(sym::hidden)
-        || inherits_doc_hidden(cx.tcx, hir_id)
-        || cx.tcx.hir().span(hir_id).in_derive_expansion()
+    if cx.tcx.is_doc_hidden(def_id.to_def_id())
+        || inherits_doc_hidden(cx.tcx, def_id)
+        || cx.tcx.def_span(def_id.to_def_id()).in_derive_expansion()
     {
         return false;
     }
-    let (level, source) = cx.tcx.lint_level_at_node(crate::lint::MISSING_DOC_CODE_EXAMPLES, hir_id);
+    let (level, source) = cx.tcx.lint_level_at_node(
+        crate::lint::MISSING_DOC_CODE_EXAMPLES,
+        cx.tcx.hir().local_def_id_to_hir_id(def_id),
+    );
     level != lint::Level::Allow || matches!(source, LintLevelSource::Default)
 }
 
index 4f0eb8b8076e5fae8214dfb8a71ace1658385d36..8435972bb11f2805ba6252f3b6eab16f2fa0bf14 100644 (file)
@@ -542,6 +542,7 @@ fn def_id_to_res(&self, ty_id: DefId) -> Option<Res> {
             | ty::Closure(..)
             | ty::Generator(..)
             | ty::GeneratorWitness(_)
+            | ty::GeneratorWitnessMIR(..)
             | ty::Dynamic(..)
             | ty::Param(_)
             | ty::Bound(..)
@@ -786,7 +787,7 @@ fn trait_impls_for<'a>(
         tcx.find_map_relevant_impl(trait_, ty, |impl_| {
             let trait_ref = tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
             // Check if these are the same type.
-            let impl_type = trait_ref.self_ty();
+            let impl_type = trait_ref.skip_binder().self_ty();
             trace!(
                 "comparing type {} with kind {:?} against type {:?}",
                 impl_type,
@@ -1194,14 +1195,9 @@ fn verify_disambiguator(
             }
 
         // item can be non-local e.g. when using #[doc(primitive = "pointer")]
-        if let Some((src_id, dst_id)) = id
-            .as_local()
-            // The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
-            // would presumably panic if a fake `DefIndex` were passed.
-            .and_then(|dst_id| {
-                item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
-            })
-        {
+        if let Some((src_id, dst_id)) = id.as_local().and_then(|dst_id| {
+            item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
+        }) {
             if self.cx.tcx.effective_visibilities(()).is_exported(src_id)
                 && !self.cx.tcx.effective_visibilities(()).is_exported(dst_id)
             {
index 42677bd8497483cce642162000a7ffc4848b07e8..f690c49005d9c70e455805f791d2d6bef49757aa 100644 (file)
@@ -2,6 +2,7 @@
 use crate::core::ResolverCaches;
 use crate::passes::collect_intra_doc_links::preprocessed_markdown_links;
 use crate::passes::collect_intra_doc_links::{Disambiguator, PreprocessedMarkdownLink};
+use crate::visit_lib::early_lib_embargo_visit_item;
 
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast::{self as ast, ItemKind};
@@ -34,6 +35,8 @@ pub(crate) fn early_resolve_intra_doc_links(
         traits_in_scope: Default::default(),
         all_trait_impls: Default::default(),
         all_macro_rules: Default::default(),
+        extern_doc_reachable: Default::default(),
+        local_doc_reachable: Default::default(),
         document_private_items,
     };
 
@@ -61,6 +64,7 @@ pub(crate) fn early_resolve_intra_doc_links(
         traits_in_scope: link_resolver.traits_in_scope,
         all_trait_impls: Some(link_resolver.all_trait_impls),
         all_macro_rules: link_resolver.all_macro_rules,
+        extern_doc_reachable: link_resolver.extern_doc_reachable,
     }
 }
 
@@ -77,6 +81,15 @@ struct EarlyDocLinkResolver<'r, 'ra> {
     traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
     all_trait_impls: Vec<DefId>,
     all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>,
+    /// This set is used as a seed for `effective_visibilities`, which are then extended by some
+    /// more items using `lib_embargo_visit_item` during doc inlining.
+    extern_doc_reachable: DefIdSet,
+    /// This is an easily identifiable superset of items added to `effective_visibilities`
+    /// using `lib_embargo_visit_item` during doc inlining.
+    /// The union of `(extern,local)_doc_reachable` is therefore a superset of
+    /// `effective_visibilities` and can be used for pruning extern impls here
+    /// in early doc link resolution.
+    local_doc_reachable: DefIdSet,
     document_private_items: bool,
 }
 
@@ -105,6 +118,10 @@ fn add_traits_in_scope(&mut self, def_id: DefId) {
         }
     }
 
+    fn is_doc_reachable(&self, def_id: DefId) -> bool {
+        self.extern_doc_reachable.contains(&def_id) || self.local_doc_reachable.contains(&def_id)
+    }
+
     /// Add traits in scope for links in impls collected by the `collect-intra-doc-links` pass.
     /// That pass filters impls using type-based information, but we don't yet have such
     /// information here, so we just conservatively calculate traits in scope for *all* modules
@@ -114,6 +131,14 @@ fn process_extern_impls(&mut self) {
         let mut start_cnum = 0;
         loop {
             let crates = Vec::from_iter(self.resolver.cstore().crates_untracked());
+            for cnum in &crates[start_cnum..] {
+                early_lib_embargo_visit_item(
+                    self.resolver,
+                    &mut self.extern_doc_reachable,
+                    cnum.as_def_id(),
+                    true,
+                );
+            }
             for &cnum in &crates[start_cnum..] {
                 let all_trait_impls =
                     Vec::from_iter(self.resolver.cstore().trait_impls_in_crate_untracked(cnum));
@@ -127,28 +152,26 @@ fn process_extern_impls(&mut self) {
                 // privacy, private traits and impls from other crates are never documented in
                 // the current crate, and links in their doc comments are not resolved.
                 for &(trait_def_id, impl_def_id, simplified_self_ty) in &all_trait_impls {
-                    if self.resolver.cstore().visibility_untracked(trait_def_id).is_public()
-                        && simplified_self_ty.and_then(|ty| ty.def()).map_or(true, |ty_def_id| {
-                            self.resolver.cstore().visibility_untracked(ty_def_id).is_public()
-                        })
+                    if self.is_doc_reachable(trait_def_id)
+                        && simplified_self_ty
+                            .and_then(|ty| ty.def())
+                            .map_or(true, |ty_def_id| self.is_doc_reachable(ty_def_id))
                     {
                         if self.visited_mods.insert(trait_def_id) {
                             self.resolve_doc_links_extern_impl(trait_def_id, false);
                         }
                         self.resolve_doc_links_extern_impl(impl_def_id, false);
                     }
+                    self.all_trait_impls.push(impl_def_id);
                 }
                 for (ty_def_id, impl_def_id) in all_inherent_impls {
-                    if self.resolver.cstore().visibility_untracked(ty_def_id).is_public() {
+                    if self.is_doc_reachable(ty_def_id) {
                         self.resolve_doc_links_extern_impl(impl_def_id, true);
                     }
                 }
                 for impl_def_id in all_incoherent_impls {
                     self.resolve_doc_links_extern_impl(impl_def_id, true);
                 }
-
-                self.all_trait_impls
-                    .extend(all_trait_impls.into_iter().map(|(_, def_id, _)| def_id));
             }
 
             if crates.len() > start_cnum {
@@ -298,6 +321,7 @@ fn process_module_children_or_reexports(&mut self, module_id: DefId) {
                     && module_id.is_local()
             {
                 if let Some(def_id) = child.res.opt_def_id() && !def_id.is_local() {
+                    self.local_doc_reachable.insert(def_id);
                     let scope_id = match child.res {
                         Res::Def(
                             DefKind::Variant
index 79db3c6c3e78699845da1046efadd30e849c33ed..7d15a207d06524b06bf3415f3621d60f6d647113 100644 (file)
@@ -7,8 +7,8 @@
 use crate::formats::cache::Cache;
 use crate::visit::DocVisitor;
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE};
 use rustc_middle::ty::{self, DefIdTree};
 use rustc_span::symbol::sym;
 
@@ -126,14 +126,14 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
     });
 
     let mut cleaner = BadImplStripper { prims, items: crate_items, cache: &cx.cache };
-    let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
+    let mut type_did_to_deref_target: DefIdMap<&Type> = DefIdMap::default();
 
     // Follow all `Deref` targets of included items and recursively add them as valid
     fn add_deref_target(
         cx: &DocContext<'_>,
-        map: &FxHashMap<DefId, &Type>,
+        map: &DefIdMap<&Type>,
         cleaner: &mut BadImplStripper<'_>,
-        targets: &mut FxHashSet<DefId>,
+        targets: &mut DefIdSet,
         type_did: DefId,
     ) {
         if let Some(target) = map.get(&type_did) {
@@ -177,7 +177,7 @@ fn add_deref_target(
                         // `Deref` target type and the impl for type positions, this map of types is keyed by
                         // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
                         if cleaner.keep_impl_with_def_id(for_did.into()) {
-                            let mut targets = FxHashSet::default();
+                            let mut targets = DefIdSet::default();
                             targets.insert(for_did);
                             add_deref_target(
                                 cx,
index 7158355ffdacc65b06457aa5dc55882ec6967a8e..03be5e799716706d2cccda938dff8a90d8154246 100644 (file)
@@ -19,8 +19,7 @@
 pub(crate) fn visit_item(cx: &DocContext<'_>, item: &clean::Item) {
     if let Some(dox) = &item.attrs.collapsed_doc_value() {
         let sp = item.attr_span(cx.tcx);
-        let extra =
-            crate::html::markdown::ExtraInfo::new_did(cx.tcx, item.item_id.expect_def_id(), sp);
+        let extra = crate::html::markdown::ExtraInfo::new(cx.tcx, item.item_id.expect_def_id(), sp);
         for code_block in markdown::rust_code_blocks(dox, &extra) {
             check_rust_syntax(cx, item, dox, code_block);
         }
@@ -73,7 +72,6 @@ fn check_rust_syntax(
             return;
         };
 
-    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
     let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced;
     let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None;
 
@@ -93,6 +91,7 @@ fn check_rust_syntax(
     // Finally build and emit the completed diagnostic.
     // All points of divergence have been handled earlier so this can be
     // done the same way whether the span is precise or not.
+    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
     cx.tcx.struct_span_lint_hir(crate::lint::INVALID_RUST_CODEBLOCKS, hir_id, sp, msg, |lint| {
         let explanation = if is_ignore {
             "`ignore` code blocks require valid Rust code for syntax highlighting; \
index de3a4b33905953c469e8831f8db80cd2e6e67680..a4bc486900b3e92e88e6e3262a2067f212b67de2 100644 (file)
@@ -9,6 +9,7 @@
 use crate::passes::Pass;
 
 use rustc_hir::def_id::LocalDefId;
+use rustc_middle::ty::DefIdTree;
 
 pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
     name: "propagate-doc-cfg",
@@ -41,24 +42,22 @@ fn merge_with_parent_attributes(&mut self, item: &mut Item) {
         let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local())
             else { return };
 
-        let hir = self.cx.tcx.hir();
-        let hir_id = hir.local_def_id_to_hir_id(def_id);
-
         if check_parent {
-            let expected_parent = hir.get_parent_item(hir_id);
+            let expected_parent = self.cx.tcx.opt_local_parent(def_id);
             // If parents are different, it means that `item` is a reexport and we need
             // to compute the actual `cfg` by iterating through its "real" parents.
-            if self.parent == Some(expected_parent.def_id) {
+            if self.parent.is_some() && self.parent == expected_parent {
                 return;
             }
         }
 
         let mut attrs = Vec::new();
-        for (parent_hir_id, _) in hir.parent_iter(hir_id) {
-            if let Some(def_id) = hir.opt_local_def_id(parent_hir_id) {
-                attrs.extend_from_slice(load_attrs(self.cx, def_id.to_def_id()));
-            }
+        let mut next_def_id = def_id;
+        while let Some(parent_def_id) = self.cx.tcx.opt_local_parent(next_def_id) {
+            attrs.extend_from_slice(load_attrs(self.cx, parent_def_id.to_def_id()));
+            next_def_id = parent_def_id;
         }
+
         let (_, cfg) = merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs));
         item.cfg = cfg;
     }
index 7db470359672f834fdaff1017f3a496a5979e28f..a89d6fa83983d685e8a6baf94d63327320beca71 100644 (file)
@@ -1,15 +1,12 @@
 //! The Rust AST Visitor. Extracts useful information and massages it into a form
 //! usable for `clean`.
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{walk_item, Visitor};
-use rustc_hir::Node;
-use rustc_hir::CRATE_HIR_ID;
-use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::TyCtxt;
+use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet};
+use rustc_hir::{Node, CRATE_HIR_ID};
+use rustc_middle::ty::{DefIdTree, TyCtxt};
 use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
@@ -26,19 +23,26 @@ pub(crate) struct Module<'hir> {
     pub(crate) name: Symbol,
     pub(crate) where_inner: Span,
     pub(crate) mods: Vec<Module<'hir>>,
-    pub(crate) id: hir::HirId,
+    pub(crate) def_id: LocalDefId,
     // (item, renamed, import_id)
-    pub(crate) items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>, Option<hir::HirId>)>,
+    pub(crate) items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>, Option<LocalDefId>)>,
     pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>,
 }
 
 impl Module<'_> {
-    pub(crate) fn new(name: Symbol, id: hir::HirId, where_inner: Span) -> Self {
-        Module { name, id, where_inner, mods: Vec::new(), items: Vec::new(), foreigns: Vec::new() }
+    pub(crate) fn new(name: Symbol, def_id: LocalDefId, where_inner: Span) -> Self {
+        Module {
+            name,
+            def_id,
+            where_inner,
+            mods: Vec::new(),
+            items: Vec::new(),
+            foreigns: Vec::new(),
+        }
     }
 
     pub(crate) fn where_outer(&self, tcx: TyCtxt<'_>) -> Span {
-        tcx.hir().span(self.id)
+        tcx.def_span(self.def_id)
     }
 }
 
@@ -49,44 +53,39 @@ fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<Symbol> {
     std::iter::once(crate_name).chain(relative).collect()
 }
 
-pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: hir::HirId) -> bool {
-    while let Some(id) = tcx.hir().get_enclosing_scope(node) {
+pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: LocalDefId) -> bool {
+    while let Some(id) = tcx.opt_local_parent(node) {
         node = id;
-        if tcx.hir().attrs(node).lists(sym::doc).has_word(sym::hidden) {
+        if tcx.is_doc_hidden(node.to_def_id()) {
             return true;
         }
     }
     false
 }
 
+// Also, is there some reason that this doesn't use the 'visit'
+// framework from syntax?.
+
 pub(crate) struct RustdocVisitor<'a, 'tcx> {
     cx: &'a mut core::DocContext<'tcx>,
-    view_item_stack: FxHashSet<hir::HirId>,
+    view_item_stack: LocalDefIdSet,
     inlining: bool,
     /// Are the current module and all of its parents public?
     inside_public_path: bool,
-    exact_paths: FxHashMap<DefId, Vec<Symbol>>,
-    modules: Vec<Module<'tcx>>,
+    exact_paths: DefIdMap<Vec<Symbol>>,
 }
 
 impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
     pub(crate) fn new(cx: &'a mut core::DocContext<'tcx>) -> RustdocVisitor<'a, 'tcx> {
         // If the root is re-exported, terminate all recursion.
-        let mut stack = FxHashSet::default();
-        stack.insert(hir::CRATE_HIR_ID);
-        let om = Module::new(
-            cx.tcx.crate_name(LOCAL_CRATE),
-            hir::CRATE_HIR_ID,
-            cx.tcx.hir().root_module().spans.inner_span,
-        );
-
+        let mut stack = LocalDefIdSet::default();
+        stack.insert(CRATE_DEF_ID);
         RustdocVisitor {
             cx,
             view_item_stack: stack,
             inlining: false,
             inside_public_path: true,
-            exact_paths: FxHashMap::default(),
-            modules: vec![om],
+            exact_paths: Default::default(),
         }
     }
 
@@ -96,10 +95,12 @@ fn store_path(&mut self, did: DefId) {
     }
 
     pub(crate) fn visit(mut self) -> Module<'tcx> {
-        let root_module = self.cx.tcx.hir().root_module();
-        self.visit_mod_contents(CRATE_HIR_ID, root_module);
-
-        let mut top_level_module = self.modules.pop().unwrap();
+        let mut top_level_module = self.visit_mod_contents(
+            CRATE_DEF_ID,
+            self.cx.tcx.hir().root_module(),
+            self.cx.tcx.crate_name(LOCAL_CRATE),
+            None,
+        );
 
         // `#[macro_export] macro_rules!` items are reexported at the top level of the
         // crate, regardless of where they're defined. We want to document the
@@ -114,13 +115,15 @@ pub(crate) fn visit(mut self) -> Module<'tcx> {
         // macro in the same module.
         let mut inserted = FxHashSet::default();
         for export in self.cx.tcx.module_reexports(CRATE_DEF_ID).unwrap_or(&[]) {
-            if let Res::Def(DefKind::Macro(_), def_id) = export.res &&
-                let Some(local_def_id) = def_id.as_local() &&
-                self.cx.tcx.has_attr(def_id, sym::macro_export) &&
-                inserted.insert(def_id)
-            {
-                    let item = self.cx.tcx.hir().expect_item(local_def_id);
-                    top_level_module.items.push((item, None, None));
+            if let Res::Def(DefKind::Macro(_), def_id) = export.res {
+                if let Some(local_def_id) = def_id.as_local() {
+                    if self.cx.tcx.has_attr(def_id, sym::macro_export) {
+                        if inserted.insert(def_id) {
+                            let item = self.cx.tcx.hir().expect_item(local_def_id);
+                            top_level_module.items.push((item, None, None));
+                        }
+                    }
+                }
             }
         }
 
@@ -154,23 +157,23 @@ pub(crate) fn visit(mut self) -> Module<'tcx> {
         top_level_module
     }
 
-    /// This method will go through the given module items in two passes:
-    /// 1. The items which are not glob imports/reexports.
-    /// 2. The glob imports/reexports.
-    fn visit_mod_contents(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>) {
-        debug!("Going through module {:?}", m);
-        let def_id = self.cx.tcx.hir().local_def_id(id).to_def_id();
+    fn visit_mod_contents(
+        &mut self,
+        def_id: LocalDefId,
+        m: &'tcx hir::Mod<'tcx>,
+        name: Symbol,
+        parent_id: Option<LocalDefId>,
+    ) -> Module<'tcx> {
+        let mut om = Module::new(name, def_id, m.spans.inner_span);
         // Keep track of if there were any private modules in the path.
         let orig_inside_public_path = self.inside_public_path;
-        self.inside_public_path &= self.cx.tcx.visibility(def_id).is_public();
-
-        // Reimplementation of `walk_mod` because we need to do it in two passes (explanations in
-        // the second loop):
+        self.inside_public_path &= self.cx.tcx.local_visibility(def_id).is_public();
         for &i in m.item_ids {
             let item = self.cx.tcx.hir().item(i);
-            if !matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
-                self.visit_item(item);
+            if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
+                continue;
             }
+            self.visit_item(item, None, &mut om, parent_id);
         }
         for &i in m.item_ids {
             let item = self.cx.tcx.hir().item(i);
@@ -178,10 +181,11 @@ fn visit_mod_contents(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>) {
             // Later passes in rustdoc will de-duplicate by name and kind, so if glob-
             // imported items appear last, then they'll be the ones that get discarded.
             if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
-                self.visit_item(item);
+                self.visit_item(item, None, &mut om, parent_id);
             }
         }
         self.inside_public_path = orig_inside_public_path;
+        om
     }
 
     /// Tries to resolve the target of a `pub use` statement and inlines the
@@ -195,10 +199,11 @@ fn visit_mod_contents(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>) {
     /// Returns `true` if the target has been inlined.
     fn maybe_inline_local(
         &mut self,
-        id: hir::HirId,
+        def_id: LocalDefId,
         res: Res,
         renamed: Option<Symbol>,
         glob: bool,
+        om: &mut Module<'tcx>,
         please_inline: bool,
     ) -> bool {
         debug!("maybe_inline_local res: {:?}", res);
@@ -212,10 +217,10 @@ fn maybe_inline_local(
             return false;
         };
 
-        let use_attrs = tcx.hir().attrs(id);
+        let use_attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id));
         // Don't inline `doc(hidden)` imports so they can be stripped at a later stage.
         let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline)
-            || use_attrs.lists(sym::doc).has_word(sym::hidden);
+            || tcx.is_doc_hidden(def_id.to_def_id());
 
         // For cross-crate impl inlining we need to know whether items are
         // reachable in documentation -- a previously unreachable item can be
@@ -226,68 +231,61 @@ fn maybe_inline_local(
             return false;
         }
 
-        let res_hir_id = match res_did.as_local() {
-            Some(n) => tcx.hir().local_def_id_to_hir_id(n),
-            None => return false,
+        let Some(res_did) = res_did.as_local() else {
+            return false;
         };
 
-        let is_private =
-            !self.cx.cache.effective_visibilities.is_directly_public(self.cx.tcx, res_did);
-        let is_hidden = inherits_doc_hidden(self.cx.tcx, res_hir_id);
+        let is_private = !self
+            .cx
+            .cache
+            .effective_visibilities
+            .is_directly_public(self.cx.tcx, res_did.to_def_id());
+        let is_hidden = inherits_doc_hidden(self.cx.tcx, res_did);
 
         // Only inline if requested or if the item would otherwise be stripped.
         if (!please_inline && !is_private && !is_hidden) || is_no_inline {
             return false;
         }
 
-        if !self.view_item_stack.insert(res_hir_id) {
+        if !self.view_item_stack.insert(res_did) {
             return false;
         }
 
-        let ret = match tcx.hir().get(res_hir_id) {
+        let ret = match tcx.hir().get_by_def_id(res_did) {
             Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => {
                 let prev = mem::replace(&mut self.inlining, true);
                 for &i in m.item_ids {
                     let i = self.cx.tcx.hir().item(i);
-                    self.visit_item_inner(i, None, Some(id));
+                    self.visit_item(i, None, om, Some(def_id));
                 }
                 self.inlining = prev;
                 true
             }
             Node::Item(it) if !glob => {
                 let prev = mem::replace(&mut self.inlining, true);
-                self.visit_item_inner(it, renamed, Some(id));
+                self.visit_item(it, renamed, om, Some(def_id));
                 self.inlining = prev;
                 true
             }
             Node::ForeignItem(it) if !glob => {
                 let prev = mem::replace(&mut self.inlining, true);
-                self.visit_foreign_item_inner(it, renamed);
+                self.visit_foreign_item(it, renamed, om);
                 self.inlining = prev;
                 true
             }
             _ => false,
         };
-        self.view_item_stack.remove(&res_hir_id);
+        self.view_item_stack.remove(&res_did);
         ret
     }
 
-    #[inline]
-    fn add_to_current_mod(
+    fn visit_item(
         &mut self,
         item: &'tcx hir::Item<'_>,
         renamed: Option<Symbol>,
-        parent_id: Option<hir::HirId>,
+        om: &mut Module<'tcx>,
+        parent_id: Option<LocalDefId>,
     ) {
-        self.modules.last_mut().unwrap().items.push((item, renamed, parent_id))
-    }
-
-    fn visit_item_inner(
-        &mut self,
-        item: &'tcx hir::Item<'_>,
-        renamed: Option<Symbol>,
-        parent_id: Option<hir::HirId>,
-    ) -> bool {
         debug!("visiting item {:?}", item);
         let name = renamed.unwrap_or(item.ident.name);
 
@@ -302,7 +300,7 @@ fn visit_item_inner(
             hir::ItemKind::ForeignMod { items, .. } => {
                 for item in items {
                     let item = self.cx.tcx.hir().foreign_item(item.id);
-                    self.visit_foreign_item_inner(item, None);
+                    self.visit_foreign_item(item, None, om);
                 }
             }
             // If we're inlining, skip private items or item reexported as "_".
@@ -331,17 +329,18 @@ fn visit_item_inner(
                         let is_glob = kind == hir::UseKind::Glob;
                         let ident = if is_glob { None } else { Some(name) };
                         if self.maybe_inline_local(
-                            item.hir_id(),
+                            item.owner_id.def_id,
                             res,
                             ident,
                             is_glob,
+                            om,
                             please_inline,
                         ) {
                             continue;
                         }
                     }
 
-                    self.add_to_current_mod(item, renamed, parent_id);
+                    om.items.push((item, renamed, parent_id))
                 }
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
@@ -361,11 +360,11 @@ fn visit_item_inner(
                 let nonexported = !self.cx.tcx.has_attr(def_id, sym::macro_export);
 
                 if is_macro_2_0 || nonexported || self.inlining {
-                    self.add_to_current_mod(item, renamed, None);
+                    om.items.push((item, renamed, None));
                 }
             }
             hir::ItemKind::Mod(ref m) => {
-                self.enter_mod(item.hir_id(), m, name);
+                om.mods.push(self.visit_mod_contents(item.owner_id.def_id, m, name, parent_id));
             }
             hir::ItemKind::Fn(..)
             | hir::ItemKind::ExternCrate(..)
@@ -376,92 +375,33 @@ fn visit_item_inner(
             | hir::ItemKind::OpaqueTy(..)
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Trait(..)
-            | hir::ItemKind::TraitAlias(..) => {
-                self.add_to_current_mod(item, renamed, parent_id);
-            }
+            | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed, parent_id)),
             hir::ItemKind::Const(..) => {
                 // Underscore constants do not correspond to a nameable item and
                 // so are never useful in documentation.
                 if name != kw::Underscore {
-                    self.add_to_current_mod(item, renamed, parent_id);
+                    om.items.push((item, renamed, parent_id));
                 }
             }
             hir::ItemKind::Impl(impl_) => {
                 // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick
                 // them up regardless of where they're located.
                 if !self.inlining && impl_.of_trait.is_none() {
-                    self.add_to_current_mod(item, None, None);
+                    om.items.push((item, None, None));
                 }
             }
         }
-        true
     }
 
-    fn visit_foreign_item_inner(
+    fn visit_foreign_item(
         &mut self,
         item: &'tcx hir::ForeignItem<'_>,
         renamed: Option<Symbol>,
+        om: &mut Module<'tcx>,
     ) {
         // If inlining we only want to include public functions.
         if !self.inlining || self.cx.tcx.visibility(item.owner_id).is_public() {
-            self.modules.last_mut().unwrap().foreigns.push((item, renamed));
+            om.foreigns.push((item, renamed));
         }
     }
-
-    /// This method will create a new module and push it onto the "modules stack" then call
-    /// `visit_mod_contents`. Once done, it'll remove it from the "modules stack" and instead
-    /// add into the list of modules of the current module.
-    fn enter_mod(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>, name: Symbol) {
-        self.modules.push(Module::new(name, id, m.spans.inner_span));
-
-        self.visit_mod_contents(id, m);
-
-        let last = self.modules.pop().unwrap();
-        self.modules.last_mut().unwrap().mods.push(last);
-    }
-}
-
-// We need to implement this visitor so it'll go everywhere and retrieve items we're interested in
-// such as impl blocks in const blocks.
-impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> {
-    type NestedFilter = nested_filter::All;
-
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
-    }
-
-    fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
-        let parent_id = if self.modules.len() > 1 {
-            Some(self.modules[self.modules.len() - 2].id)
-        } else {
-            None
-        };
-        if self.visit_item_inner(i, None, parent_id) {
-            walk_item(self, i);
-        }
-    }
-
-    fn visit_mod(&mut self, _: &hir::Mod<'tcx>, _: Span, _: hir::HirId) {
-        // Handled in `visit_item_inner`
-    }
-
-    fn visit_use(&mut self, _: &hir::UsePath<'tcx>, _: hir::HirId) {
-        // Handled in `visit_item_inner`
-    }
-
-    fn visit_path(&mut self, _: &hir::Path<'tcx>, _: hir::HirId) {
-        // Handled in `visit_item_inner`
-    }
-
-    fn visit_label(&mut self, _: &rustc_ast::Label) {
-        // Unneeded.
-    }
-
-    fn visit_infer(&mut self, _: &hir::InferArg) {
-        // Unneeded.
-    }
-
-    fn visit_lifetime(&mut self, _: &hir::Lifetime) {
-        // Unneeded.
-    }
 }
index e490559b0e92addd40d61d7f25f040749ffa4fb6..07d8b78d767dbb956994588c01ea194007ec06f0 100644 (file)
@@ -1,14 +1,14 @@
 use crate::core::DocContext;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_middle::ty::TyCtxt;
+use rustc_resolve::Resolver;
 
 // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses
 
 #[derive(Default)]
 pub(crate) struct RustdocEffectiveVisibilities {
-    extern_public: FxHashSet<DefId>,
+    extern_public: DefIdSet,
 }
 
 macro_rules! define_method {
@@ -26,6 +26,10 @@ impl RustdocEffectiveVisibilities {
     define_method!(is_directly_public);
     define_method!(is_exported);
     define_method!(is_reachable);
+
+    pub(crate) fn init(&mut self, extern_public: DefIdSet) {
+        self.extern_public = extern_public;
+    }
 }
 
 pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) {
@@ -38,14 +42,33 @@ pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) {
     .visit_item(def_id)
 }
 
+pub(crate) fn early_lib_embargo_visit_item(
+    resolver: &Resolver<'_>,
+    extern_public: &mut DefIdSet,
+    def_id: DefId,
+    is_mod: bool,
+) {
+    assert!(!def_id.is_local());
+    EarlyLibEmbargoVisitor { resolver, extern_public, visited_mods: Default::default() }
+        .visit_item(def_id, is_mod)
+}
+
 /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes
 /// specific rustdoc annotations into account (i.e., `doc(hidden)`)
 struct LibEmbargoVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     // Effective visibilities for reachable nodes
-    extern_public: &'a mut FxHashSet<DefId>,
+    extern_public: &'a mut DefIdSet,
+    // Keeps track of already visited modules, in case a module re-exports its parent
+    visited_mods: DefIdSet,
+}
+
+struct EarlyLibEmbargoVisitor<'r, 'ra> {
+    resolver: &'r Resolver<'ra>,
+    // Effective visibilities for reachable nodes
+    extern_public: &'r mut DefIdSet,
     // Keeps track of already visited modules, in case a module re-exports its parent
-    visited_mods: FxHashSet<DefId>,
+    visited_mods: DefIdSet,
 }
 
 impl LibEmbargoVisitor<'_, '_> {
@@ -72,3 +95,28 @@ fn visit_item(&mut self, def_id: DefId) {
         }
     }
 }
+
+impl EarlyLibEmbargoVisitor<'_, '_> {
+    fn visit_mod(&mut self, def_id: DefId) {
+        if !self.visited_mods.insert(def_id) {
+            return;
+        }
+
+        for item in self.resolver.cstore().module_children_untracked(def_id, self.resolver.sess()) {
+            if let Some(def_id) = item.res.opt_def_id() {
+                if item.vis.is_public() {
+                    self.visit_item(def_id, matches!(item.res, Res::Def(DefKind::Mod, _)));
+                }
+            }
+        }
+    }
+
+    fn visit_item(&mut self, def_id: DefId, is_mod: bool) {
+        if !self.resolver.cstore().is_doc_hidden_untracked(def_id) {
+            self.extern_public.insert(def_id);
+            if is_mod {
+                self.visit_mod(def_id);
+            }
+        }
+    }
+}
index 9ad24035fea8d309753f5e39e6eb53d1d0eb39ce..477e7285b12f876ad105188cfcfc8adda7dc29aa 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 9ad24035fea8d309753f5e39e6eb53d1d0eb39ce
+Subproject commit 477e7285b12f876ad105188cfcfc8adda7dc29aa
index 1cd6d3803dfb0b342272862a8590f5dfc9f72573..3c5af6bed9a1a243a693e8e22ee2486bd5b82a6c 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 1cd6d3803dfb0b342272862a8590f5dfc9f72573
+Subproject commit 3c5af6bed9a1a243a693e8e22ee2486bd5b82a6c
index 1bc457a947936b4e35fa9c9cbe8a4f945d1721e5..24e677ce8e1706bebd4def66c339c72468180845 100644 (file)
@@ -157,6 +157,11 @@ jobs:
     - name: Test metadata collection
       run: cargo collect-metadata
 
+    - name: Test lint_configuration.md is up-to-date
+      run: |
+        echo "run \`cargo collect-metadata\` if this fails"
+        git update-index --refresh
+
   integration_build:
     needs: changelog
     runs-on: ubuntu-latest
index 8e31e8f0d9815083d09b9fe971c471871e41248d..e2cde09776f4cad76d48facb72a762f2c942063d 100644 (file)
@@ -6,11 +6,204 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[4f142aa1...master](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...master)
+[d822110d...master](https://github.com/rust-lang/rust-clippy/compare/d822110d...master)
+
+## Rust 1.67
+
+Current stable, released 2023-01-26
+
+[4f142aa1...d822110d](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...d822110d)
+
+### New Lints
+
+* [`seek_from_current`]
+  [#9681](https://github.com/rust-lang/rust-clippy/pull/9681)
+* [`from_raw_with_void_ptr`]
+  [#9690](https://github.com/rust-lang/rust-clippy/pull/9690)
+* [`misnamed_getters`]
+  [#9770](https://github.com/rust-lang/rust-clippy/pull/9770)
+* [`seek_to_start_instead_of_rewind`]
+  [#9667](https://github.com/rust-lang/rust-clippy/pull/9667)
+* [`suspicious_xor_used_as_pow`]
+  [#9506](https://github.com/rust-lang/rust-clippy/pull/9506)
+* [`unnecessary_safety_doc`]
+  [#9822](https://github.com/rust-lang/rust-clippy/pull/9822)
+* [`unchecked_duration_subtraction`]
+  [#9570](https://github.com/rust-lang/rust-clippy/pull/9570)
+* [`manual_is_ascii_check`]
+  [#9765](https://github.com/rust-lang/rust-clippy/pull/9765)
+* [`unnecessary_safety_comment`]
+  [#9851](https://github.com/rust-lang/rust-clippy/pull/9851)
+* [`let_underscore_future`]
+  [#9760](https://github.com/rust-lang/rust-clippy/pull/9760)
+* [`manual_let_else`]
+  [#8437](https://github.com/rust-lang/rust-clippy/pull/8437)
+
+### Moves and Deprecations
+
+* Moved [`uninlined_format_args`] to `style` (Now warn-by-default)
+  [#9865](https://github.com/rust-lang/rust-clippy/pull/9865)
+* Moved [`needless_collect`] to `nursery` (Now allow-by-default)
+  [#9705](https://github.com/rust-lang/rust-clippy/pull/9705)
+* Moved [`or_fun_call`] to `nursery` (Now allow-by-default)
+  [#9829](https://github.com/rust-lang/rust-clippy/pull/9829)
+* Uplifted [`let_underscore_lock`] into rustc
+  [#9697](https://github.com/rust-lang/rust-clippy/pull/9697)
+* Uplifted [`let_underscore_drop`] into rustc
+  [#9697](https://github.com/rust-lang/rust-clippy/pull/9697)
+* Moved [`bool_to_int_with_if`] to `pedantic` (Now allow-by-default)
+  [#9830](https://github.com/rust-lang/rust-clippy/pull/9830)
+* Move `index_refutable_slice` to `pedantic` (Now warn-by-default)
+  [#9975](https://github.com/rust-lang/rust-clippy/pull/9975)
+* Moved [`manual_clamp`] to `nursery` (Now allow-by-default)
+  [#10101](https://github.com/rust-lang/rust-clippy/pull/10101)
+
+### Enhancements
+
+* The scope of `#![clippy::msrv]` is now tracked correctly
+  [#9924](https://github.com/rust-lang/rust-clippy/pull/9924)
+* `#[clippy::msrv]` can now be used as an outer attribute
+  [#9860](https://github.com/rust-lang/rust-clippy/pull/9860)
+* Clippy will now avoid Cargo's cache, if `Cargo.toml` or `clippy.toml` have changed
+  [#9707](https://github.com/rust-lang/rust-clippy/pull/9707)
+* [`uninlined_format_args`]: Added a new config `allow-mixed-uninlined-format-args` to allow the
+  lint, if only some arguments can be inlined
+  [#9865](https://github.com/rust-lang/rust-clippy/pull/9865)
+* [`needless_lifetimes`]: Now provides suggests for individual lifetimes
+  [#9743](https://github.com/rust-lang/rust-clippy/pull/9743)
+* [`needless_collect`]: Now detects needless `is_empty` and `contains` calls
+  [#8744](https://github.com/rust-lang/rust-clippy/pull/8744)
+* [`blanket_clippy_restriction_lints`]: Now lints, if `clippy::restriction` is enabled via the
+  command line arguments
+  [#9755](https://github.com/rust-lang/rust-clippy/pull/9755)
+* [`mutable_key_type`]: Now has the `ignore-interior-mutability` configuration, to add types which
+  should be ignored by the lint
+  [#9692](https://github.com/rust-lang/rust-clippy/pull/9692)
+* [`uninlined_format_args`]: Now works for multiline `format!` expressions
+  [#9945](https://github.com/rust-lang/rust-clippy/pull/9945)
+* [`cognitive_complexity`]: Now works for async functions
+  [#9828](https://github.com/rust-lang/rust-clippy/pull/9828)
+  [#9836](https://github.com/rust-lang/rust-clippy/pull/9836)
+* [`vec_box`]: Now avoids an off-by-one error when using the `vec-box-size-threshold` configuration
+  [#9848](https://github.com/rust-lang/rust-clippy/pull/9848)
+* [`never_loop`]: Now correctly handles breaks in nested labeled blocks
+  [#9858](https://github.com/rust-lang/rust-clippy/pull/9858)
+  [#9837](https://github.com/rust-lang/rust-clippy/pull/9837)
+* [`disallowed_methods`], [`disallowed_types`], [`disallowed_macros`]: Now correctly resolve
+  paths, if a crate is used multiple times with different versions
+  [#9800](https://github.com/rust-lang/rust-clippy/pull/9800)
+* [`disallowed_methods`]: Can now be used for local methods
+  [#9800](https://github.com/rust-lang/rust-clippy/pull/9800)
+* [`print_stdout`], [`print_stderr`]: Can now be enabled in test with the `allow-print-in-tests`
+  config value
+  [#9797](https://github.com/rust-lang/rust-clippy/pull/9797)
+* [`from_raw_with_void_ptr`]: Now works for `Rc`, `Arc`, `alloc::rc::Weak` and
+  `alloc::sync::Weak` types.
+  [#9700](https://github.com/rust-lang/rust-clippy/pull/9700)
+* [`needless_borrowed_reference`]: Now works for struct and tuple patterns with wildcards
+  [#9855](https://github.com/rust-lang/rust-clippy/pull/9855)
+* [`or_fun_call`]: Now supports `map_or` methods
+  [#9689](https://github.com/rust-lang/rust-clippy/pull/9689)
+* [`unwrap_used`], [`expect_used`]: No longer lints in test code
+  [#9686](https://github.com/rust-lang/rust-clippy/pull/9686)
+* [`fn_params_excessive_bools`]: Is now emitted with the lint level at the linted function
+  [#9698](https://github.com/rust-lang/rust-clippy/pull/9698)
+
+### False Positive Fixes
+
+* [`new_ret_no_self`]: No longer lints when `impl Trait<Self>` is returned
+  [#9733](https://github.com/rust-lang/rust-clippy/pull/9733)
+* [`unnecessary_lazy_evaluations`]: No longer lints, if the type has a significant drop
+  [#9750](https://github.com/rust-lang/rust-clippy/pull/9750)
+* [`option_if_let_else`]: No longer lints, if any arm has guard
+  [#9747](https://github.com/rust-lang/rust-clippy/pull/9747)
+* [`explicit_auto_deref`]: No longer lints, if the target type is a projection with generic
+  arguments
+  [#9813](https://github.com/rust-lang/rust-clippy/pull/9813)
+* [`unnecessary_to_owned`]: No longer lints, if the suggestion effects types
+  [#9796](https://github.com/rust-lang/rust-clippy/pull/9796)
+* [`needless_borrow`]: No longer lints, if the suggestion is affected by `Deref`
+  [#9674](https://github.com/rust-lang/rust-clippy/pull/9674)
+* [`unused_unit`]: No longer lints, if lifetimes are bound to the return type
+  [#9849](https://github.com/rust-lang/rust-clippy/pull/9849)
+* [`mut_mut`]: No longer lints cases with unsized mutable references
+  [#9835](https://github.com/rust-lang/rust-clippy/pull/9835)
+* [`bool_to_int_with_if`]: No longer lints in const context
+  [#9738](https://github.com/rust-lang/rust-clippy/pull/9738)
+* [`use_self`]: No longer lints in macros
+  [#9704](https://github.com/rust-lang/rust-clippy/pull/9704)
+* [`unnecessary_operation`]: No longer lints, if multiple macros are involved
+  [#9981](https://github.com/rust-lang/rust-clippy/pull/9981)
+* [`allow_attributes_without_reason`]: No longer lints inside external macros
+  [#9630](https://github.com/rust-lang/rust-clippy/pull/9630)
+* [`question_mark`]: No longer lints for `if let Err()` with an `else` branch
+  [#9722](https://github.com/rust-lang/rust-clippy/pull/9722)
+* [`unnecessary_cast`]: No longer lints if the identifier and cast originate from different macros
+  [#9980](https://github.com/rust-lang/rust-clippy/pull/9980)
+* [`arithmetic_side_effects`]: Now detects operations with associated constants
+  [#9592](https://github.com/rust-lang/rust-clippy/pull/9592)
+* [`explicit_auto_deref`]: No longer lints, if the initial value is not a reference or reference
+  receiver
+  [#9997](https://github.com/rust-lang/rust-clippy/pull/9997)
+* [`module_name_repetitions`], [`single_component_path_imports`]: Now handle `#[allow]`
+  attributes correctly
+  [#9879](https://github.com/rust-lang/rust-clippy/pull/9879)
+* [`bool_to_int_with_if`]: No longer lints `if let` statements
+  [#9714](https://github.com/rust-lang/rust-clippy/pull/9714)
+* [`needless_borrow`]: No longer lints, `if`-`else`-statements that require the borrow
+  [#9791](https://github.com/rust-lang/rust-clippy/pull/9791)
+* [`needless_borrow`]: No longer lints borrows, if moves were illegal
+  [#9711](https://github.com/rust-lang/rust-clippy/pull/9711)
+* [`manual_swap`]: No longer lints in const context
+  [#9871](https://github.com/rust-lang/rust-clippy/pull/9871)
+
+### Suggestion Fixes/Improvements
+
+* [`missing_safety_doc`], [`missing_errors_doc`], [`missing_panics_doc`]: No longer show the
+  entire item in the lint emission.
+  [#9772](https://github.com/rust-lang/rust-clippy/pull/9772)
+* [`needless_lifetimes`]: Only suggests `'_` when it's applicable
+  [#9743](https://github.com/rust-lang/rust-clippy/pull/9743)
+* [`use_self`]: Now suggests full paths correctly
+  [#9726](https://github.com/rust-lang/rust-clippy/pull/9726)
+* [`redundant_closure_call`]: Now correctly deals with macros during suggestion creation
+  [#9987](https://github.com/rust-lang/rust-clippy/pull/9987)
+* [`unnecessary_cast`]: Suggestions now correctly deal with references
+  [#9996](https://github.com/rust-lang/rust-clippy/pull/9996)
+* [`unnecessary_join`]: Suggestions now correctly use [turbofish] operators
+  [#9779](https://github.com/rust-lang/rust-clippy/pull/9779)
+* [`equatable_if_let`]: Can now suggest `matches!` replacements
+  [#9368](https://github.com/rust-lang/rust-clippy/pull/9368)
+* [`string_extend_chars`]: Suggestions now correctly work for `str` slices
+  [#9741](https://github.com/rust-lang/rust-clippy/pull/9741)
+* [`redundant_closure_for_method_calls`]: Suggestions now include angle brackets and generic
+  arguments if needed
+  [#9745](https://github.com/rust-lang/rust-clippy/pull/9745)
+* [`manual_let_else`]: Suggestions no longer expand macro calls
+  [#9943](https://github.com/rust-lang/rust-clippy/pull/9943)
+* [`infallible_destructuring_match`]: Suggestions now preserve references
+  [#9850](https://github.com/rust-lang/rust-clippy/pull/9850)
+* [`result_large_err`]: The error now shows the largest enum variant
+  [#9662](https://github.com/rust-lang/rust-clippy/pull/9662)
+* [`needless_return`]: Suggestions are now formatted better
+  [#9967](https://github.com/rust-lang/rust-clippy/pull/9967)
+* [`unused_rounding`]: The suggestion now preserves the original float literal notation
+  [#9870](https://github.com/rust-lang/rust-clippy/pull/9870)
+
+[turbofish]: https://turbo.fish/::%3CClippy%3E
+
+### ICE Fixes
+
+* [`result_large_err`]: Fixed ICE for empty enums
+  [#10007](https://github.com/rust-lang/rust-clippy/pull/10007)
+* [`redundant_allocation`]: Fixed ICE for types with bounded variables
+  [#9773](https://github.com/rust-lang/rust-clippy/pull/9773)
+* [`unused_rounding`]: Fixed ICE, if `_` was used as a separator
+  [#10001](https://github.com/rust-lang/rust-clippy/pull/10001)
 
 ## Rust 1.66
 
-Current stable, released 2022-12-15
+Released 2022-12-15
 
 [b52fb523...4f142aa1](https://github.com/rust-lang/rust-clippy/compare/b52fb523...4f142aa1)
 
@@ -166,6 +359,7 @@ Current stable, released 2022-12-15
 
 * [`unnecessary_to_owned`]: Avoid ICEs in favor of false negatives if information is missing
   [#9505](https://github.com/rust-lang/rust-clippy/pull/9505)
+  [#10027](https://github.com/rust-lang/rust-clippy/pull/10027)
 * [`manual_range_contains`]: No longer ICEs on values behind references
   [#9627](https://github.com/rust-lang/rust-clippy/pull/9627)
 * [`needless_pass_by_value`]: No longer ICEs on unsized `dyn Fn` arguments
@@ -4383,6 +4577,7 @@ Released 2018-09-13
 [`multi_assignments`]: https://rust-lang.github.io/rust-clippy/master/index.html#multi_assignments
 [`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
 [`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
+[`multiple_unsafe_ops_per_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_unsafe_ops_per_block
 [`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate
 [`must_use_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_unit
 [`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref
index f8cb4b7219c47467e6e41412b57f17733c02a46b..2cfb47dd758aa094688b5daba9abcccbbfaef654 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.68"
+version = "0.1.69"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
index 81254ba8b8b8f7faf163e4be75172a847cfceb4a..ab44db694835faac056a6a3e47060a0e0518821d 100644 (file)
@@ -194,11 +194,21 @@ value` mapping e.g.
 ```toml
 avoid-breaking-exported-api = false
 disallowed-names = ["toto", "tata", "titi"]
-cognitive-complexity-threshold = 30
 ```
 
-See the [list of configurable lints](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration),
-the lint descriptions contain the names and meanings of these configuration variables.
+The [table of configurations](https://doc.rust-lang.org/nightly/clippy/lint_configuration.html)
+contains all config values, their default, and a list of lints they affect.
+Each [configurable lint](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration)
+, also contains information about these values.
+
+For configurations that are a list type with default values such as
+[disallowed-names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names),
+you can use the unique value `".."` to extend the default values instead of replacing them.
+
+```toml
+# default of disallowed-names is ["foo", "baz", "quux"]
+disallowed-names = ["bar", ".."] # -> ["bar", "foo", "baz", "quux"]
+```
 
 > **Note**
 >
index 1f0b8db28a152e19c48ccd93f46285036a18e9ef..0649f7a631df426da94ae70da38a25879d9506b8 100644 (file)
@@ -5,6 +5,7 @@
 - [Installation](installation.md)
 - [Usage](usage.md)
 - [Configuration](configuration.md)
+    - [Lint Configuration](lint_configuration.md)
 - [Clippy's Lints](lints.md)
 - [Continuous Integration](continuous_integration/README.md)
     - [GitHub Actions](continuous_integration/github_actions.md)
index 430ff8b739ae861785c528b749728a199f6ee72c..87f4a697af9fd1bf1a6e4ef1f49b89adda4ae3ff 100644 (file)
@@ -8,11 +8,21 @@ basic `variable = value` mapping eg.
 ```toml
 avoid-breaking-exported-api = false
 disallowed-names = ["toto", "tata", "titi"]
-cognitive-complexity-threshold = 30
 ```
 
-See the [list of configurable lints](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration),
-the lint descriptions contain the names and meanings of these configuration variables.
+The [table of configurations](./lint_configuration.md)
+contains all config values, their default, and a list of lints they affect.
+Each [configurable lint](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration)
+, also contains information about these values.
+
+For configurations that are a list type with default values such as
+[disallowed-names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names),
+you can use the unique value `".."` to extend the default values instead of replacing them.
+
+```toml
+# default of disallowed-names is ["foo", "baz", "quux"]
+disallowed-names = ["bar", ".."] # -> ["bar", "foo", "baz", "quux"]
+```
 
 To deactivate the "for further information visit *lint-link*" message you can define the `CLIPPY_DISABLE_DOCS_LINKS`
 environment variable.
index 8b4eee8c9d94d3b3f6ddaaa72507a59de8149d70..f57dc627dce4cf8c9ceb2426b59b6862e3b27983 100644 (file)
@@ -146,7 +146,8 @@ For cargo lints, the process of testing differs in that we are interested in the
 manifest.
 
 If our new lint is named e.g. `foo_categories`, after running `cargo dev
-new_lint` we will find by default two new crates, each with its manifest file:
+new_lint --name=foo_categories --type=cargo --category=cargo` we will find by
+default two new crates, each with its manifest file:
 
 * `tests/ui-cargo/foo_categories/fail/Cargo.toml`: this file should cause the
   new lint to raise an error.
@@ -699,6 +700,10 @@ for some users. Adding a configuration is done in the following steps:
        `clippy.toml` file with the configuration value and a rust file that
        should be linted by Clippy. The test can otherwise be written as usual.
 
+5. Update [Lint Configuration](../lint_configuration.md)
+
+   Run `cargo collect-metadata` to generate documentation changes for the book.
+
 [`clippy_lints::utils::conf`]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/conf.rs
 [`clippy_lints` lib file]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs
 [`tests/ui`]: https://github.com/rust-lang/rust-clippy/blob/master/tests/ui
index a48742191850b6be852d8a5401369c03dd10884d..dbd624ecd73822174e48d002c00cbbc179f613f8 100644 (file)
@@ -3,15 +3,15 @@
 This document explains how to make additions and changes to the Clippy book, the
 guide to Clippy that you're reading right now. The Clippy book is formatted with
 [Markdown](https://www.markdownguide.org) and generated by
-[mdbook](https://github.com/rust-lang/mdBook).
+[mdBook](https://github.com/rust-lang/mdBook).
 
-- [Get mdbook](#get-mdbook)
+- [Get mdBook](#get-mdbook)
 - [Make changes](#make-changes)
 
-## Get mdbook
+## Get mdBook
 
 While not strictly necessary since the book source is simply Markdown text
-files, having mdbook locally will allow you to build, test and serve the book
+files, having mdBook locally will allow you to build, test and serve the book
 locally to view changes before you commit them to the repository. You likely
 already have `cargo` installed, so the easiest option is to simply:
 
@@ -19,7 +19,7 @@ already have `cargo` installed, so the easiest option is to simply:
 cargo install mdbook
 ```
 
-See the mdbook [installation](https://github.com/rust-lang/mdBook#installation)
+See the mdBook [installation](https://github.com/rust-lang/mdBook#installation)
 instructions for other options.
 
 ## Make changes
@@ -27,7 +27,7 @@ instructions for other options.
 The book's
 [src](https://github.com/rust-lang/rust-clippy/tree/master/book/src)
 directory contains all of the markdown files used to generate the book. If you
-want to see your changes in real time, you can use the mdbook `serve` command to
+want to see your changes in real time, you can use the mdBook `serve` command to
 run a web server locally that will automatically update changes as they are
 made. From the top level of your `rust-clippy` directory:
 
@@ -38,5 +38,5 @@ mdbook serve book --open
 Then navigate to `http://localhost:3000` to see the generated book. While the
 server is running, changes you make will automatically be updated.
 
-For more information, see the mdbook
+For more information, see the mdBook
 [guide](https://rust-lang.github.io/mdBook/).
index 80a47affe30d0c5eae3cfd392e527f129b59b4bb..d1ac7237b5e35dfcd86dfaa5659b3c14d7f76acc 100644 (file)
@@ -95,11 +95,23 @@ As section headers, we use:
 Please also be sure to update the Beta/Unreleased sections at the top with the
 relevant commit ranges.
 
-If you have the time, it would be appreciated if you double-check, that the
-`#[clippy::version]` attributes for the added lints contains the correct version.
+#### 3.1 Include `beta-accepted` PRs
+
+Look for the [`beta-accepted`] label and make sure to also include the PRs with
+that label in the changelog. If you can, remove the `beta-accepted` labels
+**after** the changelog PR was merged.
+
+> _Note:_ Some of those PRs might even got backported to the previous `beta`.
+> Those have to be included in the changelog of the _previous_ release.
+
+### 4. Update `clippy::version` attributes
+
+Next, make sure to check that the `#[clippy::version]` attributes for the added
+lints contain the correct version.
 
 [changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md
 [forge]: https://forge.rust-lang.org/
 [rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy
 [rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy
 [rust_stable_tools]: https://github.com/rust-lang/rust/releases
+[`beta-accepted`]: https://github.com/rust-lang/rust-clippy/issues?q=label%3Abeta-accepted+
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
new file mode 100644 (file)
index 0000000..f79dbb5
--- /dev/null
@@ -0,0 +1,523 @@
+<!--
+This file is generated by `cargo collect-metadata`.
+Please use that command to update the file and do not edit it by hand.
+-->
+
+## Lint Configuration Options
+| <div style="width:290px">Option</div> | Default Value |
+|--|--|
+| [arithmetic-side-effects-allowed](#arithmetic-side-effects-allowed) | `{}` |
+| [arithmetic-side-effects-allowed-binary](#arithmetic-side-effects-allowed-binary) | `[]` |
+| [arithmetic-side-effects-allowed-unary](#arithmetic-side-effects-allowed-unary) | `{}` |
+| [avoid-breaking-exported-api](#avoid-breaking-exported-api) | `true` |
+| [msrv](#msrv) | `None` |
+| [cognitive-complexity-threshold](#cognitive-complexity-threshold) | `25` |
+| [disallowed-names](#disallowed-names) | `["foo", "baz", "quux"]` |
+| [doc-valid-idents](#doc-valid-idents) | `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` |
+| [too-many-arguments-threshold](#too-many-arguments-threshold) | `7` |
+| [type-complexity-threshold](#type-complexity-threshold) | `250` |
+| [single-char-binding-names-threshold](#single-char-binding-names-threshold) | `4` |
+| [too-large-for-stack](#too-large-for-stack) | `200` |
+| [enum-variant-name-threshold](#enum-variant-name-threshold) | `3` |
+| [enum-variant-size-threshold](#enum-variant-size-threshold) | `200` |
+| [verbose-bit-mask-threshold](#verbose-bit-mask-threshold) | `1` |
+| [literal-representation-threshold](#literal-representation-threshold) | `16384` |
+| [trivial-copy-size-limit](#trivial-copy-size-limit) | `None` |
+| [pass-by-value-size-limit](#pass-by-value-size-limit) | `256` |
+| [too-many-lines-threshold](#too-many-lines-threshold) | `100` |
+| [array-size-threshold](#array-size-threshold) | `512000` |
+| [vec-box-size-threshold](#vec-box-size-threshold) | `4096` |
+| [max-trait-bounds](#max-trait-bounds) | `3` |
+| [max-struct-bools](#max-struct-bools) | `3` |
+| [max-fn-params-bools](#max-fn-params-bools) | `3` |
+| [warn-on-all-wildcard-imports](#warn-on-all-wildcard-imports) | `false` |
+| [disallowed-macros](#disallowed-macros) | `[]` |
+| [disallowed-methods](#disallowed-methods) | `[]` |
+| [disallowed-types](#disallowed-types) | `[]` |
+| [unreadable-literal-lint-fractions](#unreadable-literal-lint-fractions) | `true` |
+| [upper-case-acronyms-aggressive](#upper-case-acronyms-aggressive) | `false` |
+| [matches-for-let-else](#matches-for-let-else) | `WellKnownTypes` |
+| [cargo-ignore-publish](#cargo-ignore-publish) | `false` |
+| [standard-macro-braces](#standard-macro-braces) | `[]` |
+| [enforced-import-renames](#enforced-import-renames) | `[]` |
+| [allowed-scripts](#allowed-scripts) | `["Latin"]` |
+| [enable-raw-pointer-heuristic-for-send](#enable-raw-pointer-heuristic-for-send) | `true` |
+| [max-suggested-slice-pattern-length](#max-suggested-slice-pattern-length) | `3` |
+| [max-include-file-size](#max-include-file-size) | `1000000` |
+| [allow-expect-in-tests](#allow-expect-in-tests) | `false` |
+| [allow-unwrap-in-tests](#allow-unwrap-in-tests) | `false` |
+| [allow-dbg-in-tests](#allow-dbg-in-tests) | `false` |
+| [allow-print-in-tests](#allow-print-in-tests) | `false` |
+| [large-error-threshold](#large-error-threshold) | `128` |
+| [ignore-interior-mutability](#ignore-interior-mutability) | `["bytes::Bytes"]` |
+| [allow-mixed-uninlined-format-args](#allow-mixed-uninlined-format-args) | `true` |
+| [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` |
+
+### arithmetic-side-effects-allowed
+Suppress checking of the passed type names in all types of operations.
+
+If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead.
+
+#### Example
+
+```toml
+arithmetic-side-effects-allowed = ["SomeType", "AnotherType"]
+```
+
+#### Noteworthy
+
+A type, say `SomeType`, listed in this configuration has the same behavior of
+`["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
+
+**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
+
+* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects)
+
+
+### arithmetic-side-effects-allowed-binary
+Suppress checking of the passed type pair names in binary operations like addition or
+multiplication.
+
+Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless
+of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`.
+
+Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as
+`["AnotherType", "SomeType"]`.
+
+#### Example
+
+```toml
+arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]
+```
+
+**Default Value:** `[]` (`Vec<[String; 2]>`)
+
+* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects)
+
+
+### arithmetic-side-effects-allowed-unary
+Suppress checking of the passed type names in unary operations like "negation" (`-`).
+
+#### Example
+
+```toml
+arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
+```
+
+**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
+
+* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects)
+
+
+### avoid-breaking-exported-api
+Suppress lints whenever the suggested change would cause breakage for other crates.
+
+**Default Value:** `true` (`bool`)
+
+* [enum_variant_names](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names)
+* [large_types_passed_by_value](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value)
+* [trivially_copy_pass_by_ref](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref)
+* [unnecessary_wraps](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps)
+* [unused_self](https://rust-lang.github.io/rust-clippy/master/index.html#unused_self)
+* [upper_case_acronyms](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms)
+* [wrong_self_convention](https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention)
+* [box_collection](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection)
+* [redundant_allocation](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation)
+* [rc_buffer](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer)
+* [vec_box](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box)
+* [option_option](https://rust-lang.github.io/rust-clippy/master/index.html#option_option)
+* [linkedlist](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist)
+* [rc_mutex](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex)
+
+
+### msrv
+The minimum rust version that the project supports
+
+**Default Value:** `None` (`Option<String>`)
+
+* [manual_split_once](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once)
+* [manual_str_repeat](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat)
+* [cloned_instead_of_copied](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied)
+* [redundant_field_names](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names)
+* [redundant_static_lifetimes](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes)
+* [filter_map_next](https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next)
+* [checked_conversions](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions)
+* [manual_range_contains](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains)
+* [use_self](https://rust-lang.github.io/rust-clippy/master/index.html#use_self)
+* [mem_replace_with_default](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default)
+* [manual_non_exhaustive](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive)
+* [option_as_ref_deref](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref)
+* [map_unwrap_or](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or)
+* [match_like_matches_macro](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro)
+* [manual_strip](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip)
+* [missing_const_for_fn](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn)
+* [unnested_or_patterns](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns)
+* [from_over_into](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into)
+* [ptr_as_ptr](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr)
+* [if_then_some_else_none](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none)
+* [approx_constant](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant)
+* [deprecated_cfg_attr](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr)
+* [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice)
+* [map_clone](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone)
+* [borrow_as_ptr](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr)
+* [manual_bits](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits)
+* [err_expect](https://rust-lang.github.io/rust-clippy/master/index.html#err_expect)
+* [cast_abs_to_unsigned](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned)
+* [uninlined_format_args](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args)
+* [manual_clamp](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp)
+* [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else)
+* [unchecked_duration_subtraction](https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction)
+
+
+### cognitive-complexity-threshold
+The maximum cognitive complexity a function can have
+
+**Default Value:** `25` (`u64`)
+
+* [cognitive_complexity](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity)
+
+
+### disallowed-names
+The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
+`".."` can be used as part of the list to indicate, that the configured values should be appended to the
+default configuration of Clippy. By default any configuration will replace the default value.
+
+**Default Value:** `["foo", "baz", "quux"]` (`Vec<String>`)
+
+* [disallowed_names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names)
+
+
+### doc-valid-idents
+The list of words this lint should not consider as identifiers needing ticks. The value
+`".."` can be used as part of the list to indicate, that the configured values should be appended to the
+default configuration of Clippy. By default any configuraction will replace the default value. For example:
+* `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
+* `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
+
+Default list:
+
+**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` (`Vec<String>`)
+
+* [doc_markdown](https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown)
+
+
+### too-many-arguments-threshold
+The maximum number of argument a function or method can have
+
+**Default Value:** `7` (`u64`)
+
+* [too_many_arguments](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments)
+
+
+### type-complexity-threshold
+The maximum complexity a type can have
+
+**Default Value:** `250` (`u64`)
+
+* [type_complexity](https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity)
+
+
+### single-char-binding-names-threshold
+The maximum number of single char bindings a scope may have
+
+**Default Value:** `4` (`u64`)
+
+* [many_single_char_names](https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names)
+
+
+### too-large-for-stack
+The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
+
+**Default Value:** `200` (`u64`)
+
+* [boxed_local](https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local)
+* [useless_vec](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec)
+
+
+### enum-variant-name-threshold
+The minimum number of enum variants for the lints about variant names to trigger
+
+**Default Value:** `3` (`u64`)
+
+* [enum_variant_names](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names)
+
+
+### enum-variant-size-threshold
+The maximum size of an enum's variant to avoid box suggestion
+
+**Default Value:** `200` (`u64`)
+
+* [large_enum_variant](https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant)
+
+
+### verbose-bit-mask-threshold
+The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
+
+**Default Value:** `1` (`u64`)
+
+* [verbose_bit_mask](https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask)
+
+
+### literal-representation-threshold
+The lower bound for linting decimal literals
+
+**Default Value:** `16384` (`u64`)
+
+* [decimal_literal_representation](https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation)
+
+
+### trivial-copy-size-limit
+The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
+
+**Default Value:** `None` (`Option<u64>`)
+
+* [trivially_copy_pass_by_ref](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref)
+
+
+### pass-by-value-size-limit
+The minimum size (in bytes) to consider a type for passing by reference instead of by value.
+
+**Default Value:** `256` (`u64`)
+
+* [large_type_pass_by_move](https://rust-lang.github.io/rust-clippy/master/index.html#large_type_pass_by_move)
+
+
+### too-many-lines-threshold
+The maximum number of lines a function or method can have
+
+**Default Value:** `100` (`u64`)
+
+* [too_many_lines](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines)
+
+
+### array-size-threshold
+The maximum allowed size for arrays on the stack
+
+**Default Value:** `512000` (`u128`)
+
+* [large_stack_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays)
+* [large_const_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays)
+
+
+### vec-box-size-threshold
+The size of the boxed type in bytes, where boxing in a `Vec` is allowed
+
+**Default Value:** `4096` (`u64`)
+
+* [vec_box](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box)
+
+
+### max-trait-bounds
+The maximum number of bounds a trait can have to be linted
+
+**Default Value:** `3` (`u64`)
+
+* [type_repetition_in_bounds](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds)
+
+
+### max-struct-bools
+The maximum number of bool fields a struct can have
+
+**Default Value:** `3` (`u64`)
+
+* [struct_excessive_bools](https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools)
+
+
+### max-fn-params-bools
+The maximum number of bool parameters a function can have
+
+**Default Value:** `3` (`u64`)
+
+* [fn_params_excessive_bools](https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools)
+
+
+### warn-on-all-wildcard-imports
+Whether to allow certain wildcard imports (prelude, super in tests).
+
+**Default Value:** `false` (`bool`)
+
+* [wildcard_imports](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports)
+
+
+### disallowed-macros
+The list of disallowed macros, written as fully qualified paths.
+
+**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
+
+* [disallowed_macros](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros)
+
+
+### disallowed-methods
+The list of disallowed methods, written as fully qualified paths.
+
+**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
+
+* [disallowed_methods](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods)
+
+
+### disallowed-types
+The list of disallowed types, written as fully qualified paths.
+
+**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
+
+* [disallowed_types](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types)
+
+
+### unreadable-literal-lint-fractions
+Should the fraction of a decimal be linted to include separators.
+
+**Default Value:** `true` (`bool`)
+
+* [unreadable_literal](https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal)
+
+
+### upper-case-acronyms-aggressive
+Enables verbose mode. Triggers if there is more than one uppercase char next to each other
+
+**Default Value:** `false` (`bool`)
+
+* [upper_case_acronyms](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms)
+
+
+### matches-for-let-else
+Whether the matches should be considered by the lint, and whether there should
+be filtering for common types.
+
+**Default Value:** `WellKnownTypes` (`crate::manual_let_else::MatchLintBehaviour`)
+
+* [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else)
+
+
+### cargo-ignore-publish
+For internal testing only, ignores the current `publish` settings in the Cargo manifest.
+
+**Default Value:** `false` (`bool`)
+
+* [_cargo_common_metadata](https://rust-lang.github.io/rust-clippy/master/index.html#_cargo_common_metadata)
+
+
+### standard-macro-braces
+Enforce the named macros always use the braces specified.
+
+A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
+is could be used with a full path two `MacroMatcher`s have to be added one with the full path
+`crate_name::macro_name` and one with just the macro name.
+
+**Default Value:** `[]` (`Vec<crate::nonstandard_macro_braces::MacroMatcher>`)
+
+* [nonstandard_macro_braces](https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces)
+
+
+### enforced-import-renames
+The list of imports to always rename, a fully qualified path followed by the rename.
+
+**Default Value:** `[]` (`Vec<crate::utils::conf::Rename>`)
+
+* [missing_enforced_import_renames](https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames)
+
+
+### allowed-scripts
+The list of unicode scripts allowed to be used in the scope.
+
+**Default Value:** `["Latin"]` (`Vec<String>`)
+
+* [disallowed_script_idents](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents)
+
+
+### enable-raw-pointer-heuristic-for-send
+Whether to apply the raw pointer heuristic to determine if a type is `Send`.
+
+**Default Value:** `true` (`bool`)
+
+* [non_send_fields_in_send_ty](https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty)
+
+
+### max-suggested-slice-pattern-length
+When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in
+the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed.
+For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
+
+**Default Value:** `3` (`u64`)
+
+* [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice)
+
+
+### max-include-file-size
+The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
+
+**Default Value:** `1000000` (`u64`)
+
+* [large_include_file](https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file)
+
+
+### allow-expect-in-tests
+Whether `expect` should be allowed within `#[cfg(test)]`
+
+**Default Value:** `false` (`bool`)
+
+* [expect_used](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used)
+
+
+### allow-unwrap-in-tests
+Whether `unwrap` should be allowed in test cfg
+
+**Default Value:** `false` (`bool`)
+
+* [unwrap_used](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used)
+
+
+### allow-dbg-in-tests
+Whether `dbg!` should be allowed in test functions
+
+**Default Value:** `false` (`bool`)
+
+* [dbg_macro](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro)
+
+
+### allow-print-in-tests
+Whether print macros (ex. `println!`) should be allowed in test functions
+
+**Default Value:** `false` (`bool`)
+
+* [print_stdout](https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout)
+* [print_stderr](https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr)
+
+
+### large-error-threshold
+The maximum size of the `Err`-variant in a `Result` returned from a function
+
+**Default Value:** `128` (`u64`)
+
+* [result_large_err](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err)
+
+
+### ignore-interior-mutability
+A list of paths to types that should be treated like `Arc`, i.e. ignored but
+for the generic parameters for determining interior mutability
+
+**Default Value:** `["bytes::Bytes"]` (`Vec<String>`)
+
+* [mutable_key](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key)
+
+
+### allow-mixed-uninlined-format-args
+Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
+
+**Default Value:** `true` (`bool`)
+
+* [uninlined_format_args](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args)
+
+
+### suppress-restriction-lint-in-const
+In same
+cases the restructured operation might not be unavoidable, as the
+suggested counterparts are unavailable in constant code. This
+configuration will cause restriction lints to trigger even
+if no suggestion can be made.
+
+**Default Value:** `false` (`bool`)
+
+* [indexing_slicing](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing)
+
+
+
index a9f69b1ba6300907b1ec7c4770a53ab98f9eceba..4c40483e3ec948bf02a9044a24936e2e0eac7f13 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.68"
+version = "0.1.69"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
index 82d368bb8bc2c1e127d74f8c07530e152c2ba84c..556fa579000c6767109ba58123fed76dbd8f14ff 100644 (file)
@@ -1,10 +1,11 @@
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
-use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait};
+use clippy_utils::ty::{implements_trait, is_copy};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Lit};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::Ident;
 
@@ -43,9 +44,7 @@ fn is_bool_lit(e: &Expr<'_>) -> bool {
     ) && !e.span.from_expansion()
 }
 
-fn is_impl_not_trait_with_bool_out(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    let ty = cx.typeck_results().expr_ty(e);
-
+fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     cx.tcx
         .lang_items()
         .not_trait()
@@ -77,31 +76,57 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             return;
         }
         let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
-        if !(is_bool_lit(a) ^ is_bool_lit(b)) {
+
+        let a_span = a.span.source_callsite();
+        let b_span = b.span.source_callsite();
+
+        let (lit_span, non_lit_expr) = match (is_bool_lit(a), is_bool_lit(b)) {
+            // assert_eq!(true, b)
+            //            ^^^^^^
+            (true, false) => (a_span.until(b_span), b),
+            // assert_eq!(a, true)
+            //             ^^^^^^
+            (false, true) => (b_span.with_lo(a_span.hi()), a),
             // If there are two boolean arguments, we definitely don't understand
             // what's going on, so better leave things as is...
             //
             // Or there is simply no boolean and then we can leave things as is!
-            return;
-        }
+            _ => return,
+        };
 
-        if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) {
+        let non_lit_ty = cx.typeck_results().expr_ty(non_lit_expr);
+
+        if !is_impl_not_trait_with_bool_out(cx, non_lit_ty) {
             // At this point the expression which is not a boolean
             // literal does not implement Not trait with a bool output,
             // so we cannot suggest to rewrite our code
             return;
         }
 
+        if !is_copy(cx, non_lit_ty) {
+            // Only lint with types that are `Copy` because `assert!(x)` takes
+            // ownership of `x` whereas `assert_eq(x, true)` does not
+            return;
+        }
+
         let macro_name = macro_name.as_str();
         let non_eq_mac = &macro_name[..macro_name.len() - 3];
-        span_lint_and_sugg(
+        span_lint_and_then(
             cx,
             BOOL_ASSERT_COMPARISON,
             macro_call.span,
             &format!("used `{macro_name}!` with a literal bool"),
-            "replace it with",
-            format!("{non_eq_mac}!(..)"),
-            Applicability::MaybeIncorrect,
+            |diag| {
+                // assert_eq!(...)
+                // ^^^^^^^^^
+                let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!');
+
+                diag.multipart_suggestion(
+                    format!("replace it with `{non_eq_mac}!(..)`"),
+                    vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())],
+                    Applicability::MachineApplicable,
+                );
+            },
         );
     }
 }
index 939bdbcdc7cd7e245b733bed959c419f0b336f76..e8106beec37423b191d554b31c4700f8922bb776 100644 (file)
@@ -6,9 +6,10 @@
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
-use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, UnOp};
+use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 use rustc_span::sym;
 
@@ -82,7 +83,7 @@ fn check_fn(
         _: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         _: Span,
-        _: HirId,
+        _: LocalDefId,
     ) {
         NonminimalBoolVisitor { cx }.visit_body(body);
     }
index 9409f4844f54b4140217260c97d1f9f09e32f8e4..1633ffd589c384ab827cdf224a1749c00b2ce8b6 100644 (file)
@@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
         && let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind
         && method_name.ident.name == rustc_span::sym::as_ptr
         && let Some(as_ptr_did) = cx.typeck_results().type_dependent_def_id(cast_expr.peel_blocks().hir_id)
-        && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did)
+        && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).subst_identity()
         && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next()
         && let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind()
         && let Some(recv) = snippet_opt(cx, receiver.span)
index a6376484914ba11dad3b13e0ef9fe649a9f8493c..f3f8b8d87982e6aee6eae51bd47c6cf18fe3646a 100644 (file)
@@ -1,11 +1,14 @@
 use clippy_utils::consts::{constant, Constant};
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::expr_or_init;
+use clippy_utils::source::snippet;
 use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
+use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, FloatTy, Ty};
+use rustc_span::Span;
 use rustc_target::abi::IntegerType;
 
 use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION};
@@ -74,7 +77,14 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
     }
 }
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    cast_expr: &Expr<'_>,
+    cast_from: Ty<'_>,
+    cast_to: Ty<'_>,
+    cast_to_span: Span,
+) {
     let msg = match (cast_from.kind(), cast_to.is_integral()) {
         (ty::Int(_) | ty::Uint(_), true) => {
             let from_nbits = apply_reductions(
@@ -139,7 +149,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
                 );
                 return;
             }
-            format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",)
+            format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}")
         },
 
         (ty::Float(_), true) => {
@@ -153,5 +163,19 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
         _ => return,
     };
 
-    span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg);
+    let name_of_cast_from = snippet(cx, cast_expr.span, "..");
+    let cast_to_snip = snippet(cx, cast_to_span, "..");
+    let suggestion = format!("{cast_to_snip}::try_from({name_of_cast_from})");
+
+    span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| {
+        diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...");
+        diag.span_suggestion_with_style(
+            expr.span,
+            "... or use `try_from` and handle the error accordingly",
+            suggestion,
+            Applicability::Unspecified,
+            // always show the suggestion in a separate line
+            SuggestionStyle::ShowAlways,
+        );
+    });
 }
index 161e3a698e9ea6133ba0d6a86e2ad70983d7dbf8..362f70d12d185344181f2e7524dcc977890488e8 100644 (file)
@@ -80,7 +80,8 @@
     /// ### What it does
     /// Checks for casts between numerical types that may
     /// truncate large values. This is expected behavior, so the cast is `Allow` by
-    /// default.
+    /// default. It suggests user either explicitly ignore the lint,
+    /// or use `try_from()` and handle the truncation, default, or panic explicitly.
     ///
     /// ### Why is this bad?
     /// In some problem domains, it is good practice to avoid
     ///     x as u8
     /// }
     /// ```
+    /// Use instead:
+    /// ```
+    /// fn as_u8(x: u64) -> u8 {
+    ///     if let Ok(x) = u8::try_from(x) {
+    ///         x
+    ///     } else {
+    ///         todo!();
+    ///     }
+    /// }
+    /// // Or
+    /// #[allow(clippy::cast_possible_truncation)]
+    /// fn as_u16(x: u64) -> u16 {
+    ///     x as u16
+    /// }
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub CAST_POSSIBLE_TRUNCATION,
     pedantic,
@@ -712,7 +728,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
 
             if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
-                cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
+                cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span);
                 if cast_from.is_numeric() {
                     cast_possible_wrap::check(cx, expr, cast_from, cast_to);
                     cast_precision_loss::check(cx, expr, cast_from, cast_to);
index 1c3a89a97824c31ccdb1f4888fb2b85eb67b88ff..e8531157e0f7a538465c5adf5b3c4d055ea322d1 100644 (file)
@@ -8,9 +8,10 @@
 use core::ops::ControlFlow;
 use rustc_ast::ast::Attribute;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 use rustc_span::{sym, BytePos};
 
@@ -140,9 +141,8 @@ fn check_fn(
         decl: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         span: Span,
-        hir_id: HirId,
+        def_id: LocalDefId,
     ) {
-        let def_id = cx.tcx.hir().local_def_id(hir_id);
         if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) {
             let expr = if is_async_fn(kind) {
                 match get_async_fn_body(cx.tcx, body) {
index 91ca73633f062d7e0f1c3e10ac31b3ef085ec297..36a366fc97474b98ff457a6493e2fa9ecd8ef343 100644 (file)
     crate::module_style::MOD_MODULE_FILES_INFO,
     crate::module_style::SELF_NAMED_MODULE_FILES_INFO,
     crate::multi_assignments::MULTI_ASSIGNMENTS_INFO,
+    crate::multiple_unsafe_ops_per_block::MULTIPLE_UNSAFE_OPS_PER_BLOCK_INFO,
     crate::mut_key::MUTABLE_KEY_TYPE_INFO,
     crate::mut_mut::MUT_MUT_INFO,
     crate::mut_reference::UNNECESSARY_MUT_PASSED_INFO,
index 03460689e19ad7a5bdac313b6c2f6eade3fb7b77..f806ba238c7c670c0d068700a7a8acf28f2e2671 100644 (file)
@@ -141,7 +141,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 
             ExprKind::MethodCall(_, receiver, args, _) => {
                 if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
-                    let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
+                    let fn_sig = self.cx.tcx.fn_sig(def_id).subst_identity().skip_binder();
                     for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) {
                         self.ty_bounds.push((*bound).into());
                         self.visit_expr(expr);
@@ -215,7 +215,7 @@ fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'
     let node_ty = cx.typeck_results().node_type_opt(hir_id)?;
     // We can't use `Ty::fn_sig` because it automatically performs substs, this may result in FNs.
     match node_ty.kind() {
-        ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id)),
+        ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id).subst_identity()),
         ty::FnPtr(fn_sig) => Some(*fn_sig),
         _ => None,
     }
index 05f2b92c037093affa39e21fe5ac1dc058528cb6..6c333afacc648b41d567d36b9b782095d8936fce 100644 (file)
@@ -759,7 +759,7 @@ fn walk_parents<'tcx>(
             }) if span.ctxt() == ctxt => {
                 let output = cx
                     .tcx
-                    .erase_late_bound_regions(cx.tcx.fn_sig(owner_id.to_def_id()).output());
+                    .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
                 Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx))
             },
 
@@ -778,20 +778,20 @@ fn walk_parents<'tcx>(
 
             Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
                 ExprKind::Ret(_) => {
-                    let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap());
+                    let owner_id = cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap());
                     Some(
                         if let Node::Expr(
                             closure_expr @ Expr {
                                 kind: ExprKind::Closure(closure),
                                 ..
                             },
-                        ) = cx.tcx.hir().get(owner_id)
+                        ) = cx.tcx.hir().get_by_def_id(owner_id)
                         {
                             closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
                         } else {
                             let output = cx
                                 .tcx
-                                .erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).output());
+                                .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
                             ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)
                         },
                     )
@@ -858,7 +858,7 @@ fn walk_parents<'tcx>(
                             && let subs = cx
                                 .typeck_results()
                                 .node_substs_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default()
-                            && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
+                            && let impl_ty = if cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[0].is_ref() {
                                 // Trait methods taking `&self`
                                 sub_ty
                             } else {
@@ -879,7 +879,7 @@ fn walk_parents<'tcx>(
                         return Some(Position::MethodReceiver);
                     }
                     args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
-                        let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
+                        let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i + 1];
                         // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
                         // `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782
                         if e.hir_id == child_id && method.args.is_none() && let ty::Param(param_ty) = ty.kind() {
@@ -896,7 +896,7 @@ fn walk_parents<'tcx>(
                         } else {
                             ty_auto_deref_stability(
                                 cx,
-                                cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
+                                cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).subst_identity().input(i + 1)),
                                 precedence,
                             )
                             .position_for_arg()
@@ -1093,7 +1093,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
     let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
 
     let Some(callee_def_id) = fn_def_id(cx, parent) else { return Position::Other(precedence) };
-    let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+    let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
     let substs_with_expr_ty = cx
         .typeck_results()
         .node_substs(if let ExprKind::Call(callee, _) = parent.kind {
@@ -1221,7 +1221,7 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
         .in_definition_order()
         .any(|assoc_item| {
             if assoc_item.fn_has_self_parameter {
-                let self_ty = cx.tcx.fn_sig(assoc_item.def_id).skip_binder().inputs()[0];
+                let self_ty = cx.tcx.fn_sig(assoc_item.def_id).subst_identity().skip_binder().inputs()[0];
                 matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Mut))
             } else {
                 false
@@ -1419,6 +1419,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
             | ty::FnDef(..)
             | ty::Generator(..)
             | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..)
             | ty::Closure(..)
             | ty::Never
             | ty::Tuple(_)
index f4b15e0916dbf47bca1aa427e5d46f35d9bfa45a..f8fc726d603f8dd5a32fdc1f5c740de1871f4f01 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
 use rustc_hir::{
-    self as hir, BlockCheckMode, BodyId, Constness, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, UnsafeSource,
+    self as hir, BlockCheckMode, BodyId, Constness, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource,
     Unsafety,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -18,6 +18,7 @@
     TraitPredicate, Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 use rustc_span::sym;
 
@@ -251,7 +252,7 @@ fn check_hash_peq<'tcx>(
 
                 // Only care about `impl PartialEq<Foo> for Foo`
                 // For `impl PartialEq<B> for A, input_types is [A, B]
-                if trait_ref.substs.type_at(1) == ty {
+                if trait_ref.subst_identity().substs.type_at(1) == ty {
                     span_lint_and_then(
                         cx,
                         DERIVED_HASH_WITH_MANUAL_EQ,
@@ -299,7 +300,7 @@ fn check_ord_partial_ord<'tcx>(
 
                 // Only care about `impl PartialOrd<Foo> for Foo`
                 // For `impl PartialOrd<B> for A, input_types is [A, B]
-                if trait_ref.substs.type_at(1) == ty {
+                if trait_ref.subst_identity().substs.type_at(1) == ty {
                     let mess = if partial_ord_is_automatically_derived {
                         "you are implementing `Ord` explicitly but have derived `PartialOrd`"
                     } else {
@@ -425,7 +426,7 @@ struct UnsafeVisitor<'a, 'tcx> {
 impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: HirId) {
+    fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: LocalDefId) {
         if self.has_unsafe {
             return;
         }
index cdc23a4d22739ef79ebc7993a88ea902de69e617..127201b72e275948a46124bcb0c3cb7e97fac2e7 100644 (file)
@@ -23,7 +23,6 @@
 use rustc_parse::parser::ForceCollect;
 use rustc_session::parse::ParseSess;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::def_id::LocalDefId;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::{BytePos, FilePathMapping, SourceMap, Span};
 use rustc_span::{sym, FileName, Pos};
     ///     unimplemented!();
     /// }
     /// ```
-    #[clippy::version = "1.66.0"]
+    #[clippy::version = "1.67.0"]
     pub UNNECESSARY_SAFETY_DOC,
     restriction,
     "`pub fn` or `pub trait` with `# Safety` docs"
@@ -302,7 +301,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                         panic_span: None,
                     };
                     fpu.visit_expr(body.value);
-                    lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span);
+                    lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span);
                 }
             },
             hir::ItemKind::Impl(impl_) => {
@@ -338,7 +337,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitIte
         let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return };
         if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
             if !in_external_macro(cx.tcx.sess, item.span) {
-                lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, None, None);
+                lint_for_missing_headers(cx, item.owner_id, sig, headers, None, None);
             }
         }
     }
@@ -357,20 +356,20 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
                 panic_span: None,
             };
             fpu.visit_expr(body.value);
-            lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span);
+            lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span);
         }
     }
 }
 
 fn lint_for_missing_headers(
     cx: &LateContext<'_>,
-    def_id: LocalDefId,
+    owner_id: hir::OwnerId,
     sig: &hir::FnSig<'_>,
     headers: DocHeaders,
     body_id: Option<hir::BodyId>,
     panic_span: Option<Span>,
 ) {
-    if !cx.effective_visibilities.is_exported(def_id) {
+    if !cx.effective_visibilities.is_exported(owner_id.def_id) {
         return; // Private functions do not require doc comments
     }
 
@@ -378,13 +377,13 @@ fn lint_for_missing_headers(
     if cx
         .tcx
         .hir()
-        .parent_iter(cx.tcx.hir().local_def_id_to_hir_id(def_id))
+        .parent_iter(owner_id.into())
         .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id)))
     {
         return;
     }
 
-    let span = cx.tcx.def_span(def_id);
+    let span = cx.tcx.def_span(owner_id);
     match (headers.safety, sig.header.unsafety) {
         (false, hir::Unsafety::Unsafe) => span_lint(
             cx,
@@ -411,8 +410,7 @@ fn lint_for_missing_headers(
         );
     }
     if !headers.errors {
-        let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
-        if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::Result) {
+        if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) {
             span_lint(
                 cx,
                 MISSING_ERRORS_DOC,
index b77b5621b4c68be05a7fef4177687bbb13e823e4..4c69dacf381ad66b9ce96ca0baacd6fc3ba5fc63 100644 (file)
@@ -277,7 +277,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
                                 Some(c) if is_word_beginning(c) => span_lint(
                                     cx,
                                     MODULE_NAME_REPETITIONS,
-                                    item.span,
+                                    item.ident.span,
                                     "item name starts with its containing module's name",
                                 ),
                                 _ => (),
@@ -287,7 +287,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
                             span_lint(
                                 cx,
                                 MODULE_NAME_REPETITIONS,
-                                item.span,
+                                item.ident.span,
                                 "item name ends with its containing module's name",
                             );
                         }
index dfb43893326eb8a225ee72b7ef0ce5feaecd0886..d6ab4c25e83ef9a4593be1406173c043fd5c2585 100644 (file)
@@ -8,6 +8,7 @@
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, TraitRef, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::kw;
 use rustc_target::spec::abi::Abi;
@@ -63,7 +64,7 @@ fn check_fn(
         _: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         _: Span,
-        hir_id: HirId,
+        fn_def_id: LocalDefId,
     ) {
         if let Some(header) = fn_kind.header() {
             if header.abi != Abi::Rust {
@@ -71,7 +72,11 @@ fn check_fn(
             }
         }
 
-        let parent_id = cx.tcx.hir().get_parent_item(hir_id).def_id;
+        let parent_id = cx
+            .tcx
+            .hir()
+            .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(fn_def_id))
+            .def_id;
         let parent_node = cx.tcx.hir().find_by_def_id(parent_id);
 
         let mut trait_self_ty = None;
@@ -84,7 +89,7 @@ fn check_fn(
             // find `self` ty for this trait if relevant
             if let ItemKind::Trait(_, _, _, _, items) = item.kind {
                 for trait_item in items {
-                    if trait_item.id.hir_id() == hir_id {
+                    if trait_item.id.owner_id.def_id == fn_def_id {
                         // be sure we have `self` parameter in this function
                         if trait_item.kind == (AssocItemKind::Fn { has_self: true }) {
                             trait_self_ty = Some(
@@ -105,7 +110,6 @@ fn check_fn(
             too_large_for_stack: self.too_large_for_stack,
         };
 
-        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
         let infcx = cx.tcx.infer_ctxt().build();
         ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
 
index fc2912f696e0384baa554564d683d4ba23f80fcd..9d089fcad70e695ccf8cf04160de13b42dccd497 100644 (file)
@@ -1,10 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::{get_parent_as_impl, has_repr_attr, is_bool};
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, FnDecl, HirId, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty};
+use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
+use rustc_span::def_id::LocalDefId;
 use rustc_target::spec::abi::Abi;
 
 declare_clippy_lint! {
@@ -168,8 +169,9 @@ fn check_fn(
         fn_decl: &'tcx FnDecl<'tcx>,
         _: &'tcx Body<'tcx>,
         span: Span,
-        hir_id: HirId,
+        def_id: LocalDefId,
     ) {
+        let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
         if let Some(fn_header) = fn_kind.header()
             && fn_header.abi == Abi::Rust
             && get_parent_as_impl(cx.tcx, hir_id)
index 1fece5d1c480917f606856b1896611b8f3d2016e..9fd13084dc9e860b191a8e5de5f5b23e77ba5686 100644 (file)
@@ -79,8 +79,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
             then {
                 let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
                     if v.fields().iter().any(|f| {
-                        let def_id = cx.tcx.hir().local_def_id(f.hir_id);
-                        !cx.tcx.visibility(def_id).is_public()
+                        !cx.tcx.visibility(f.def_id).is_public()
                     }) {
                         // skip structs with private fields
                         return;
index 9a1058470e18e6155af9a4c5a1ee711dde9553da..2ef547526d4f7961027d20dbb77f7e846435b992 100644 (file)
@@ -56,7 +56,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
         if_chain! {
             if let hir::ItemKind::Impl(impl_) = &item.kind;
             if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
-            if cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.def_id);
+            if cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.skip_binder().def_id);
             then {
                 lint_impl_body(cx, item.span, impl_.items);
             }
index 043112bbc95967dc66c3814e3d02013ff76932cf..d376ad3bfe3998cc1e48a7d927efd68bfcdbbfaa 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,
@@ -311,6 +311,10 @@ fn check_uninlined_args(
     // in those cases, make the code suggestion hidden
     let multiline_fix = fixes.iter().any(|(span, _)| cx.sess().source_map().is_multiline(*span));
 
+    // Suggest removing each argument only once, for example in `format!("{0} {0}", arg)`.
+    fixes.sort_unstable_by_key(|(span, _)| *span);
+    fixes.dedup_by_key(|(span, _)| *span);
+
     span_lint_and_then(
         cx,
         UNINLINED_FORMAT_ARGS,
index a92f7548ff254d16a2f51b255675650d139e8734..bd66ace4500a8d305f55ec1e430e1785e09d3348 100644 (file)
@@ -76,7 +76,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             && let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
             // `impl Into<target_ty> for self_ty`
             && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
-            && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+            && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(ty::EarlyBinder::subst_identity)
             && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
             && !matches!(middle_trait_ref.substs.type_at(1).kind(), ty::Alias(ty::Opaque, _))
         {
index 00f5ba56496ecd5486a2c395f3d28a4fdcf2e6a6..096508dc4f11e24dd135ed9d41e8ffeca79b1f41 100644 (file)
@@ -31,7 +31,7 @@
     /// let _ = unsafe { Box::from_raw(ptr as *mut usize) };
     /// ```
     ///
-    #[clippy::version = "1.66.0"]
+    #[clippy::version = "1.67.0"]
     pub FROM_RAW_WITH_VOID_PTR,
     suspicious,
     "creating a `Box` from a void raw pointer"
index 27acad45ccf729e00e63982d50ead26f92ec6b7b..d6b50537c2e1d91e97195eeadbac58df8c5a9604 100644 (file)
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
-use rustc_hir::{intravisit::FnKind, Body, ExprKind, FnDecl, HirId, ImplicitSelfKind, Unsafety};
+use rustc_hir::{intravisit::FnKind, Body, ExprKind, FnDecl, ImplicitSelfKind, Unsafety};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_span::Span;
@@ -16,7 +16,6 @@ pub fn check_fn(
     decl: &FnDecl<'_>,
     body: &Body<'_>,
     span: Span,
-    _hir_id: HirId,
 ) {
     let FnKind::Method(ref ident, sig) = kind else {
             return;
index 9dbce3f889bef117ddfcbba93d9de08a85bd60bf..4399c68e130f7b7330c1c2a6f782d26ab297fc1d 100644 (file)
@@ -9,6 +9,7 @@
 use rustc_hir::intravisit;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -363,12 +364,13 @@ fn check_fn(
         decl: &'tcx hir::FnDecl<'_>,
         body: &'tcx hir::Body<'_>,
         span: Span,
-        hir_id: hir::HirId,
+        def_id: LocalDefId,
     ) {
+        let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
         too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold);
         too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold);
-        not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, hir_id);
-        misnamed_getters::check_fn(cx, kind, decl, body, span, hir_id);
+        not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id);
+        misnamed_getters::check_fn(cx, kind, decl, body, span);
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
index d22bede36b419944b372f84594dd294b926442e1..29bdc46b647d5a8b807803d34f56949d5e0289bb 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_ast::ast::Attribute;
 use rustc_errors::Applicability;
-use rustc_hir::def_id::{DefIdSet, LocalDefId};
+use rustc_hir::def_id::DefIdSet;
 use rustc_hir::{self as hir, def::Res, QPath};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::{
@@ -27,14 +27,14 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
         let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         if let Some(attr) = attr {
-            check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
+            check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
         } else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
             check_must_use_candidate(
                 cx,
                 sig.decl,
                 cx.tcx.hir().body(*body_id),
                 item.span,
-                item.owner_id.def_id,
+                item.owner_id,
                 item.span.with_hi(sig.decl.output.span().hi()),
                 "this function could have a `#[must_use]` attribute",
             );
@@ -49,7 +49,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
         let attrs = cx.tcx.hir().attrs(item.hir_id());
         let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
         if let Some(attr) = attr {
-            check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
+            check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
         } else if is_public
             && !is_proc_macro(cx.sess(), attrs)
             && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
@@ -59,7 +59,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
                 sig.decl,
                 cx.tcx.hir().body(*body_id),
                 item.span,
-                item.owner_id.def_id,
+                item.owner_id,
                 item.span.with_hi(sig.decl.output.span().hi()),
                 "this method could have a `#[must_use]` attribute",
             );
@@ -75,7 +75,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
         let attrs = cx.tcx.hir().attrs(item.hir_id());
         let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
         if let Some(attr) = attr {
-            check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
+            check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
         } else if let hir::TraitFn::Provided(eid) = *eid {
             let body = cx.tcx.hir().body(eid);
             if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) {
@@ -84,7 +84,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
                     sig.decl,
                     body,
                     item.span,
-                    item.owner_id.def_id,
+                    item.owner_id,
                     item.span.with_hi(sig.decl.output.span().hi()),
                     "this method could have a `#[must_use]` attribute",
                 );
@@ -96,7 +96,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
 fn check_needless_must_use(
     cx: &LateContext<'_>,
     decl: &hir::FnDecl<'_>,
-    item_id: hir::HirId,
+    item_id: hir::OwnerId,
     item_span: Span,
     fn_header_span: Span,
     attr: &Attribute,
@@ -131,7 +131,7 @@ fn check_must_use_candidate<'tcx>(
     decl: &'tcx hir::FnDecl<'_>,
     body: &'tcx hir::Body<'_>,
     item_span: Span,
-    item_id: LocalDefId,
+    item_id: hir::OwnerId,
     fn_span: Span,
     msg: &str,
 ) {
@@ -139,8 +139,8 @@ fn check_must_use_candidate<'tcx>(
         || mutates_static(cx, body)
         || in_external_macro(cx.sess(), item_span)
         || returns_unit(decl)
-        || !cx.effective_visibilities.is_exported(item_id)
-        || is_must_use_ty(cx, return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(item_id)))
+        || !cx.effective_visibilities.is_exported(item_id.def_id)
+        || is_must_use_ty(cx, return_ty(cx, item_id))
     {
         return;
     }
index 2c0bf551fd7e2b790c5c5896b85d3e327740d79d..a13909a2cdb8fe9016ebc016eebc35285ba0f489 100644 (file)
@@ -17,7 +17,7 @@ pub(super) fn check_fn<'tcx>(
     kind: intravisit::FnKind<'tcx>,
     decl: &'tcx hir::FnDecl<'tcx>,
     body: &'tcx hir::Body<'tcx>,
-    hir_id: hir::HirId,
+    def_id: LocalDefId,
 ) {
     let unsafety = match kind {
         intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }) => unsafety,
@@ -25,7 +25,7 @@ pub(super) fn check_fn<'tcx>(
         intravisit::FnKind::Closure => return,
     };
 
-    check_raw_ptr(cx, unsafety, decl, body, cx.tcx.hir().local_def_id(hir_id));
+    check_raw_ptr(cx, unsafety, decl, body, def_id)
 }
 
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
@@ -58,7 +58,7 @@ fn check_raw_ptr<'tcx>(
                     },
                     hir::ExprKind::MethodCall(_, recv, args, _) => {
                         let def_id = typeck.type_dependent_def_id(e.hir_id).unwrap();
-                        if cx.tcx.fn_sig(def_id).skip_binder().unsafety == hir::Unsafety::Unsafe {
+                        if cx.tcx.fn_sig(def_id).skip_binder().skip_binder().unsafety == hir::Unsafety::Unsafe {
                             check_arg(cx, &raw_ptrs, recv);
                             for arg in args {
                                 check_arg(cx, &raw_ptrs, arg);
index 23da145d038257be75f38c88c8247ac55aaa169a..fa2a9b30c058d1605a6048f85b0dfe2d14487bc5 100644 (file)
@@ -21,7 +21,7 @@ fn result_err_ty<'tcx>(
 ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
     if !in_external_macro(cx.sess(), item_span)
         && let hir::FnRetTy::Return(hir_ty) = decl.output
-        && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).output())
+        && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).subst_identity().output())
         && is_type_diagnostic_item(cx, ty, sym::Result)
         && let ty::Adt(_, substs) = ty.kind()
     {
index 989f83cf80d5972301fc06eef9604796f674a7b8..9fb73a371b8f478505a64142671b96256328c1bf 100644 (file)
@@ -1,11 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::return_ty;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, FnDecl, HirId};
+use rustc_hir::{Body, FnDecl};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, AliasTy, Clause, EarlyBinder, PredicateKind};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::{sym, Span};
 use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
 use rustc_trait_selection::traits::{self, FulfillmentError};
@@ -56,12 +57,12 @@ fn check_fn(
         decl: &'tcx FnDecl<'tcx>,
         _: &'tcx Body<'tcx>,
         _: Span,
-        hir_id: HirId,
+        fn_def_id: LocalDefId,
     ) {
         if let FnKind::Closure = kind {
             return;
         }
-        let ret_ty = return_ty(cx, hir_id);
+        let ret_ty = return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(fn_def_id).expect_owner());
         if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() {
             let preds = cx.tcx.explicit_item_bounds(def_id);
             let mut is_future = false;
@@ -78,7 +79,7 @@ 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 cause = traits::ObligationCause::misc(span, fn_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 946d04eff6f9850f6c81dce875bca890f0b9d76f..372b6ead3fe4685e6206645e17ec3a3dbd696207 100644 (file)
@@ -11,6 +11,7 @@
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::{Span, SyntaxContext};
 
 declare_clippy_lint! {
@@ -223,7 +224,7 @@ fn check_fn(
         decl: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         span: Span,
-        _: HirId,
+        _: LocalDefId,
     ) {
         if (!matches!(kind, FnKind::Closure) && matches!(decl.output, FnRetTy::DefaultReturn(_)))
             || span.ctxt() != body.value.span.ctxt()
index c5abcc462545c935fb8a6b37e678685ce7bf639b..e9b2e31a769ad5a216a3375d9be6a52f9e4f2e24 100644 (file)
@@ -52,21 +52,19 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
         // List of spans to lint. (lint_span, first_span)
         let mut lint_spans = Vec::new();
 
-        for (_, impl_ids) in cx
+        let inherent_impls = cx
             .tcx
-            .crate_inherent_impls(())
-            .inherent_impls
-            .iter()
-            .filter(|(&id, impls)| {
-                impls.len() > 1
-                    // Check for `#[allow]` on the type definition
-                    && !is_lint_allowed(
-                        cx,
-                        MULTIPLE_INHERENT_IMPL,
-                        cx.tcx.hir().local_def_id_to_hir_id(id),
-                    )
-            })
-        {
+            .with_stable_hashing_context(|hcx| cx.tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true));
+
+        for (_, impl_ids) in inherent_impls.into_iter().filter(|(&id, impls)| {
+            impls.len() > 1
+            // Check for `#[allow]` on the type definition
+            && !is_lint_allowed(
+                cx,
+                MULTIPLE_INHERENT_IMPL,
+                cx.tcx.hir().local_def_id_to_hir_id(id),
+            )
+        }) {
             for impl_id in impl_ids.iter().map(|id| id.expect_local()) {
                 match type_map.entry(cx.tcx.type_of(impl_id)) {
                     Entry::Vacant(e) => {
index aaecc4fa8f25698e68b705906deba938d01ed6f8..d43e5cc9b2c3d23c84edc14c121c5e2a2c654337 100644 (file)
@@ -105,7 +105,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<
             if impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }));
 
             // Check if return type is String
-            if is_type_lang_item(cx, return_ty(cx, impl_item.hir_id()), LangItem::String);
+            if is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String);
 
             // Filters instances of to_string which are required by a trait
             if trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none();
@@ -124,7 +124,7 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
         .expect("Failed to get trait ID of `Display`!");
 
     // Get the real type of 'self'
-    let self_type = cx.tcx.fn_sig(item.owner_id).input(0);
+    let self_type = cx.tcx.fn_sig(item.owner_id).skip_binder().input(0);
     let self_type = self_type.skip_binder().peel_refs();
 
     // Emit either a warning or an error
index dd1b23e7d9d29f19a513b36efbc1468e690907b0..668110c7cc081c1e9da0fd1e62897c9d9d1dc757 100644 (file)
@@ -59,9 +59,9 @@
     ///
     /// [`Duration`]: std::time::Duration
     /// [`Instant::now()`]: std::time::Instant::now;
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.67.0"]
     pub UNCHECKED_DURATION_SUBTRACTION,
-    suspicious,
+    pedantic,
     "finds unchecked subtraction of a 'Duration' from an 'Instant'"
 }
 
index e76de77f195d7aedd1357fdaafbcfeb253c3feaf..7557a9ce13f1119d276f66beb3fcc26e260578eb 100644 (file)
@@ -66,7 +66,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>
 
 fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
     if sig.decl.implicit_self.has_implicit_self() {
-        let ret_ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(fn_id).output());
+        let ret_ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(fn_id).subst_identity().output());
         let ret_ty = cx
             .tcx
             .try_normalize_erasing_regions(cx.param_env, ret_ty)
index 9eba46756299c57bc178a48fc92b65a4af99fc38..80ed2862a419a9edb8fc6f759b9ad397a6e3e832 100644 (file)
@@ -144,7 +144,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>)
             if let Some(local_id) = ty_id.as_local();
             let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
             if !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id);
-            if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).skip_binder());
+            if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder());
             then {
                 let (name, kind) = match cx.tcx.hir().find(ty_hir_id) {
                     Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"),
@@ -196,7 +196,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
     fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool {
         item.ident.name == name
             && if let AssocItemKind::Fn { has_self } = item.kind {
-                has_self && { cx.tcx.fn_sig(item.id.owner_id).inputs().skip_binder().len() == 1 }
+                has_self && { cx.tcx.fn_sig(item.id.owner_id).skip_binder().inputs().skip_binder().len() == 1 }
             } else {
                 false
             }
@@ -219,12 +219,12 @@ fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) {
         let is_empty = sym!(is_empty);
 
         let is_empty_method_found = current_and_super_traits
-            .iter()
+            .items()
             .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty))
             .any(|i| {
                 i.kind == ty::AssocKind::Fn
                     && i.fn_has_self_parameter
-                    && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
+                    && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1
             });
 
         if !is_empty_method_found {
@@ -342,7 +342,7 @@ fn check_for_is_empty<'tcx>(
         ),
         Some(is_empty)
             if !(is_empty.fn_has_self_parameter
-                && check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).skip_binder(), self_kind, output)) =>
+                && check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).subst_identity().skip_binder(), self_kind, output)) =>
         {
             (
                 format!(
@@ -473,7 +473,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     /// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
     fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
         if item.kind == ty::AssocKind::Fn {
-            let sig = cx.tcx.fn_sig(item.def_id);
+            let sig = cx.tcx.fn_sig(item.def_id).skip_binder();
             let ty = sig.skip_binder();
             ty.inputs().len() == 1
         } else {
index 61f87b91400d76405f8fcb914066040f49a9b4ff..f8e3595098088402e4414c9fb73e1f01b47fac9a 100644 (file)
@@ -84,7 +84,7 @@
     /// let _ = foo().await;
     /// # }
     /// ```
-    #[clippy::version = "1.66"]
+    #[clippy::version = "1.67.0"]
     pub LET_UNDERSCORE_FUTURE,
     suspicious,
     "non-binding `let` on a future"
index d8e2ae02c5a65cf1467d0cfee62e5edbf87c14dc..d06830397761bd4b9d52997caaaf2c024820c34a 100644 (file)
@@ -1,7 +1,6 @@
 #![feature(array_windows)]
 #![feature(binary_heap_into_iter_sorted)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(drain_filter)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 mod mixed_read_write_in_expression;
 mod module_style;
 mod multi_assignments;
+mod multiple_unsafe_ops_per_block;
 mod mut_key;
 mod mut_mut;
 mod mut_reference;
@@ -908,6 +908,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
     store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
     store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
+    store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
index 7cf1a6b8084a613b9053e2c1fe18bd2498f590d8..747a94ba5a6edc23bf08c77b494393b2e9e75fbe 100644 (file)
@@ -15,7 +15,6 @@
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter as middle_nested_filter;
-use rustc_middle::ty::TyCtxt;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
@@ -154,7 +153,7 @@ fn check_fn_inner<'tcx>(
         .filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
 
     for typ in types {
-        for pred in generics.bounds_for_param(cx.tcx.hir().local_def_id(typ.hir_id)) {
+        for pred in generics.bounds_for_param(typ.def_id) {
             if pred.origin == PredicateOrigin::WhereClause {
                 // has_where_lifetimes checked that this predicate contains no lifetime.
                 continue;
@@ -251,7 +250,7 @@ fn could_use_elision<'tcx>(
     // level of the current item.
 
     // check named LTs
-    let allowed_lts = allowed_lts_from(cx.tcx, named_generics);
+    let allowed_lts = allowed_lts_from(named_generics);
 
     // these will collect all the lifetimes for references in arg/return types
     let mut input_visitor = RefVisitor::new(cx);
@@ -360,11 +359,11 @@ fn could_use_elision<'tcx>(
     }
 }
 
-fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
+fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
     let mut allowed_lts = FxHashSet::default();
     for par in named_generics.iter() {
         if let GenericParamKind::Lifetime { .. } = par.kind {
-            allowed_lts.insert(RefLt::Named(tcx.hir().local_def_id(par.hir_id)));
+            allowed_lts.insert(RefLt::Named(par.def_id));
         }
     }
     allowed_lts.insert(RefLt::Unnamed);
@@ -516,7 +515,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
                     return true;
                 }
                 // if the bounds define new lifetimes, they are fine to occur
-                let allowed_lts = allowed_lts_from(cx.tcx, pred.bound_generic_params);
+                let allowed_lts = allowed_lts_from(pred.bound_generic_params);
                 // now walk the bounds
                 for bound in pred.bounds.iter() {
                     walk_param_bound(&mut visitor, bound);
index 3bca93d80aa7f7540dfdecd9243f32bda0ed8c06..e6ed4ea7a5db550c0b80944f7c9d5930250423d8 100644 (file)
@@ -370,7 +370,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             ExprKind::MethodCall(_, receiver, args, _) => {
                 let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
                 for (ty, expr) in iter::zip(
-                    self.cx.tcx.fn_sig(def_id).inputs().skip_binder(),
+                    self.cx.tcx.fn_sig(def_id).subst_identity().inputs().skip_binder(),
                     std::iter::once(receiver).chain(args.iter()),
                 ) {
                     self.prefer_mutable = false;
index a63422d2a36ac530c14b75843a7bd38905c58774..d1a1f773f87b3b0878b83ab05a261a8ea89ab4c9 100644 (file)
@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'
         } else {
             return;
         };
-    let mutable_static_in_cond = var_visitor.def_ids.iter().any(|(_, v)| *v);
+    let mutable_static_in_cond = var_visitor.def_ids.items().any(|(_, v)| *v);
 
     let mut has_break_or_return_visitor = HasBreakOrReturnVisitor {
         has_break_or_return: false,
index 63212beaa63dd6b584685baf4650f718f8d0df2e..3778eb4c732d7ea73686ab434b0b9513fd68f0fa 100644 (file)
@@ -6,10 +6,11 @@
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound,
-    HirId, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
+    ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
@@ -45,7 +46,7 @@ fn check_fn(
         decl: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         span: Span,
-        _: HirId,
+        _: LocalDefId,
     ) {
         if_chain! {
             if let Some(header) = kind.header();
index d9ef7dffa020dbbd6d24715a35129fa72f88bcf2..2fd32c009eaa79374cbc9f5c8aabb915e41e7b84 100644 (file)
@@ -43,7 +43,7 @@
     ///     'A'.is_ascii_uppercase();
     /// }
     /// ```
-    #[clippy::version = "1.66.0"]
+    #[clippy::version = "1.67.0"]
     pub MANUAL_IS_ASCII_CHECK,
     style,
     "use dedicated method to check ascii range"
index bca193be9e711a520e3e4774c0c55a6af72559b8..9a84068d4487b3054607d5babc643b30aa15f5ac 100644 (file)
@@ -157,11 +157,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
             && def.variants.len() > 1
         {
             let mut iter = def.variants.iter().filter_map(|v| {
-                let id = cx.tcx.hir().local_def_id(v.hir_id);
-                (matches!(v.data, hir::VariantData::Unit(..))
+                (matches!(v.data, hir::VariantData::Unit(_, _))
                     && v.ident.as_str().starts_with('_')
                     && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)))
-                .then_some((id, v.span))
+                .then_some((v.def_id, v.span))
             });
             if let Some((id, span)) = iter.next()
                 && iter.next().is_none()
index 59195d1ae4e0a5854865b83243de49155df97f83..edcab6968cbe0aaead4427e61b4d20de4a09d8cd 100644 (file)
@@ -104,7 +104,7 @@ fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
 
     if let ty::FnDef(id, _) = *ty.kind() {
-        if let Some(fn_type) = cx.tcx.fn_sig(id).no_bound_vars() {
+        if let Some(fn_type) = cx.tcx.fn_sig(id).subst_identity().no_bound_vars() {
             return is_unit_type(fn_type.output());
         }
     }
index ac61b4377885b8cfd2a179c901ee844be0cd8aef..5e01ed90ff0997402337ae9cba753f55495c2fb4 100644 (file)
@@ -54,7 +54,7 @@ fn collect_replace_calls<'tcx>(
                 from_args.push_front(from);
                 ControlFlow::Continue(())
             } else {
-                ControlFlow::BREAK
+                ControlFlow::Break(())
             }
         } else {
             ControlFlow::Continue(())
index a9189b31c57108990d96fbe740632ede6cb3c6f6..aed0ad5d9b5a78fe231beceff720413bc65f5287 100644 (file)
@@ -70,7 +70,7 @@ fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
                 if let hir::ExprKind::Path(ref p) = fun.kind {
                     match cx.qpath_res(p, fun.hir_id) {
                         hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
-                            cx.tcx.fn_sig(def_id).output().skip_binder().kind(),
+                            cx.tcx.fn_sig(def_id).subst_identity().output().skip_binder().kind(),
                             ty::Ref(re, ..) if re.is_static(),
                         ),
                         _ => false,
@@ -84,7 +84,7 @@ fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
                     .type_dependent_def_id(arg.hir_id)
                     .map_or(false, |method_id| {
                         matches!(
-                            cx.tcx.fn_sig(method_id).output().skip_binder().kind(),
+                            cx.tcx.fn_sig(method_id).subst_identity().output().skip_binder().kind(),
                             ty::Ref(re, ..) if re.is_static()
                         )
                     })
index 77be61b4793403d2a9ba489df6daab12103b8841..fb94dfa5980b76f05a9b002a765961379f3138b6 100644 (file)
     ///     Ok(())
     /// }
     /// ```
-    #[clippy::version = "1.66.0"]
+    #[clippy::version = "1.67.0"]
     pub SEEK_FROM_CURRENT,
     complexity,
     "use dedicated method for seek from current position"
     ///     t.rewind();
     /// }
     /// ```
-    #[clippy::version = "1.66.0"]
+    #[clippy::version = "1.67.0"]
     pub SEEK_TO_START_INSTEAD_OF_REWIND,
     complexity,
     "jumping to the start of stream using `seek` method"
@@ -3352,7 +3352,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
 
         let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
         if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind {
-            let method_sig = cx.tcx.fn_sig(impl_item.owner_id);
+            let method_sig = cx.tcx.fn_sig(impl_item.owner_id).subst_identity();
             let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
             let first_arg_ty_opt = method_sig.inputs().iter().next().copied();
             // if this impl block implements a trait, lint in trait definition instead
@@ -3412,7 +3412,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
         }
 
         if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
-            let ret_ty = return_ty(cx, impl_item.hir_id());
+            let ret_ty = return_ty(cx, impl_item.owner_id);
 
             if contains_ty_adt_constructor_opaque(cx, ret_ty, self_ty) {
                 return;
@@ -3460,7 +3460,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
         if_chain! {
             if item.ident.name == sym::new;
             if let TraitItemKind::Fn(_, _) = item.kind;
-            let ret_ty = return_ty(cx, item.hir_id());
+            let ret_ty = return_ty(cx, item.owner_id);
             let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
                 .self_ty()
                 .skip_binder();
index f4d3ef3b742509f40debe7616bb272b7f295f274..82d3b830d4f3949c498c672280097b18dc7167d6 100644 (file)
@@ -137,7 +137,7 @@ pub(super) fn check<'tcx>(
 /// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool`
 fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool {
     cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| {
-        let sig = cx.tcx.fn_sig(id).skip_binder();
+        let sig = cx.tcx.fn_sig(id).subst_identity().skip_binder();
         sig.inputs().len() == 1 && sig.output().is_bool()
     })
 }
@@ -165,7 +165,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty:
 fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -> bool {
     let typeck = cx.typeck_results();
     if let Some(id) = typeck.type_dependent_def_id(call_id)
-        && let sig = cx.tcx.fn_sig(id)
+        && let sig = cx.tcx.fn_sig(id).subst_identity()
         && sig.skip_binder().output().is_bool()
         && let [_, search_ty] = *sig.skip_binder().inputs()
         && let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.erase_late_bound_regions(sig.rebind(search_ty)).kind()
index 2ac0786b37b1e73fd431cd3267c30b0992bed0b3..0dc7fe2a2c5a36d900e9a43b61829a86d664ab1d 100644 (file)
 pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
     if_chain! {
         if is_trait_method(cx, count_recv, sym::Iterator);
-        let closure = expr_or_init(cx, map_arg);
-        if let Some(def_id) = cx.tcx.hir().opt_local_def_id(closure.hir_id);
-        if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id);
-        let closure_body = cx.tcx.hir().body(body_id);
+        if let hir::ExprKind::Closure(closure) = expr_or_init(cx, map_arg).kind;
+        let closure_body = cx.tcx.hir().body(closure.body);
         if !cx.typeck_results().expr_ty(closure_body.value).is_unit();
         then {
             if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) {
index 9263f0519724bcaa58d30f45ef2c05d6569ec230..4e5af1c7c71249bba4dab76cba74386d2214e484 100644 (file)
@@ -246,7 +246,7 @@ fn check_other_call_arg<'tcx>(
     if_chain! {
         if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
         if let Some((callee_def_id, _, recv, call_args)) = get_callee_substs_and_args(cx, maybe_call);
-        let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+        let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
         if let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id);
         if let Some(input) = fn_sig.inputs().get(i);
         let (input, n_refs) = peel_mid_ty_refs(*input);
@@ -368,10 +368,9 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
             Node::Block(..) => continue,
             Node::Item(item) => {
                 if let ItemKind::Fn(_, _, body_id) = &item.kind
-                && let output_ty = return_ty(cx, item.hir_id())
-                && let local_def_id = cx.tcx.hir().local_def_id(item.hir_id())
-                && Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
-                    let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.hir_id());
+                && let output_ty = return_ty(cx, item.owner_id)
+                && Inherited::build(cx.tcx, item.owner_id.def_id).enter(|inherited| {
+                    let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.owner_id.def_id);
                     fn_ctxt.can_coerce(ty, output_ty)
                 }) {
                     if has_lifetime(output_ty) && has_lifetime(ty) {
@@ -386,7 +385,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
             Node::Expr(parent_expr) => {
                 if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
                 {
-                    let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+                    let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
                     if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
                         && let Some(param_ty) = fn_sig.inputs().get(arg_index)
                         && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
index 9f4beb92b9d2e77bc265e5f13eb3b050989fc77a..0705029a613bba3e1f863e46eb68ca82bdcd73eb 100644 (file)
@@ -4,12 +4,13 @@
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind,
-    Stmt, StmtKind, TyKind,
+    self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, Stmt,
+    StmtKind, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::{ExpnKind, Span};
 
@@ -151,7 +152,7 @@ fn check_fn(
         decl: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         span: Span,
-        _: HirId,
+        _: LocalDefId,
     ) {
         if let FnKind::Closure = k {
             // Does not apply to closures
index 5bc04bc17fb4f00bdf2cba1c1d9db4b08e8991a4..87bd007a26a241e7dcbf43bca5d01a10932ab39a 100644 (file)
@@ -6,11 +6,12 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
+use rustc_hir::{Body, Constness, FnDecl, GenericParamKind};
 use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -91,14 +92,12 @@ fn check_fn(
         _: &FnDecl<'_>,
         body: &Body<'tcx>,
         span: Span,
-        hir_id: HirId,
+        def_id: LocalDefId,
     ) {
         if !self.msrv.meets(msrvs::CONST_IF_MATCH) {
             return;
         }
 
-        let def_id = cx.tcx.hir().local_def_id(hir_id);
-
         if in_external_macro(cx.tcx.sess, span) || is_entrypoint_fn(cx, def_id.to_def_id()) {
             return;
         }
@@ -132,6 +131,8 @@ fn check_fn(
             FnKind::Closure => return,
         }
 
+        let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
+
         // Const fns are not allowed as methods in a trait.
         {
             let parent = cx.tcx.hir().get_parent_item(hir_id).def_id;
index 758ce47cf114b8dc3aba594b3ba2ad3d24710a72..5a459548153aab242c7a0d4b6aa800e50d522fc2 100644 (file)
@@ -155,7 +155,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
         let container_id = assoc_item.container_id(cx.tcx);
         let trait_def_id = match assoc_item.container {
             TraitContainer => Some(container_id),
-            ImplContainer => cx.tcx.impl_trait_ref(container_id).map(|t| t.def_id),
+            ImplContainer => cx.tcx.impl_trait_ref(container_id).map(|t| t.skip_binder().def_id),
         };
 
         if let Some(trait_def_id) = trait_def_id {
index 68af8a672f6aed19b7e7f22f235a6255129a2abc..e99081ad06202313b8bf2b2dd4c0f22060aaa150 100644 (file)
@@ -80,19 +80,21 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
                 }
             }
 
-            for assoc in provided.values() {
-                let source_map = cx.tcx.sess.source_map();
-                let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id));
+            cx.tcx.with_stable_hashing_context(|hcx| {
+                for assoc in provided.values_sorted(&hcx, true) {
+                    let source_map = cx.tcx.sess.source_map();
+                    let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id));
 
-                span_lint_and_help(
-                    cx,
-                    MISSING_TRAIT_METHODS,
-                    source_map.guess_head_span(item.span),
-                    &format!("missing trait method provided by default: `{}`", assoc.name),
-                    Some(definition_span),
-                    "implement the method",
-                );
-            }
+                    span_lint_and_help(
+                        cx,
+                        MISSING_TRAIT_METHODS,
+                        source_map.guess_head_span(item.span),
+                        &format!("missing trait method provided by default: `{}`", assoc.name),
+                        Some(definition_span),
+                        "implement the method",
+                    );
+                }
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
new file mode 100644 (file)
index 0000000..2814c92
--- /dev/null
@@ -0,0 +1,185 @@
+use clippy_utils::{
+    diagnostics::span_lint_and_then,
+    visitors::{for_each_expr_with_closures, Descend, Visitable},
+};
+use core::ops::ControlFlow::Continue;
+use hir::{
+    def::{DefKind, Res},
+    BlockCheckMode, ExprKind, QPath, UnOp, Unsafety,
+};
+use rustc_ast::Mutability;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `unsafe` blocks that contain more than one unsafe operation.
+    ///
+    /// ### Why is this bad?
+    /// Combined with `undocumented_unsafe_blocks`,
+    /// this lint ensures that each unsafe operation must be independently justified.
+    /// Combined with `unused_unsafe`, this lint also ensures
+    /// elimination of unnecessary unsafe blocks through refactoring.
+    ///
+    /// ### Example
+    /// ```rust
+    /// /// Reads a `char` from the given pointer.
+    /// ///
+    /// /// # Safety
+    /// ///
+    /// /// `ptr` must point to four consecutive, initialized bytes which
+    /// /// form a valid `char` when interpreted in the native byte order.
+    /// fn read_char(ptr: *const u8) -> char {
+    ///     // SAFETY: The caller has guaranteed that the value pointed
+    ///     // to by `bytes` is a valid `char`.
+    ///     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// /// Reads a `char` from the given pointer.
+    /// ///
+    /// /// # Safety
+    /// ///
+    /// /// - `ptr` must be 4-byte aligned, point to four consecutive
+    /// ///   initialized bytes, and be valid for reads of 4 bytes.
+    /// /// - The bytes pointed to by `ptr` must represent a valid
+    /// ///   `char` when interpreted in the native byte order.
+    /// fn read_char(ptr: *const u8) -> char {
+    ///     // SAFETY: `ptr` is 4-byte aligned, points to four consecutive
+    ///     // initialized bytes, and is valid for reads of 4 bytes.
+    ///     let int_value = unsafe { *ptr.cast::<u32>() };
+    ///
+    ///     // SAFETY: The caller has guaranteed that the four bytes
+    ///     // pointed to by `bytes` represent a valid `char`.
+    ///     unsafe { char::from_u32_unchecked(int_value) }
+    /// }
+    /// ```
+    #[clippy::version = "1.68.0"]
+    pub MULTIPLE_UNSAFE_OPS_PER_BLOCK,
+    restriction,
+    "more than one unsafe operation per `unsafe` block"
+}
+declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK]);
+
+impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock {
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
+        if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) {
+            return;
+        }
+        let mut unsafe_ops = vec![];
+        collect_unsafe_exprs(cx, block, &mut unsafe_ops);
+        if unsafe_ops.len() > 1 {
+            span_lint_and_then(
+                cx,
+                MULTIPLE_UNSAFE_OPS_PER_BLOCK,
+                block.span,
+                &format!(
+                    "this `unsafe` block contains {} unsafe operations, expected only one",
+                    unsafe_ops.len()
+                ),
+                |diag| {
+                    for (msg, span) in unsafe_ops {
+                        diag.span_note(span, msg);
+                    }
+                },
+            );
+        }
+    }
+}
+
+fn collect_unsafe_exprs<'tcx>(
+    cx: &LateContext<'tcx>,
+    node: impl Visitable<'tcx>,
+    unsafe_ops: &mut Vec<(&'static str, Span)>,
+) {
+    for_each_expr_with_closures(cx, node, |expr| {
+        match expr.kind {
+            ExprKind::InlineAsm(_) => unsafe_ops.push(("inline assembly used here", expr.span)),
+
+            ExprKind::Field(e, _) => {
+                if cx.typeck_results().expr_ty(e).is_union() {
+                    unsafe_ops.push(("union field access occurs here", expr.span));
+                }
+            },
+
+            ExprKind::Path(QPath::Resolved(
+                _,
+                hir::Path {
+                    res: Res::Def(DefKind::Static(Mutability::Mut), _),
+                    ..
+                },
+            )) => {
+                unsafe_ops.push(("access of a mutable static occurs here", expr.span));
+            },
+
+            ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty_adjusted(e).is_unsafe_ptr() => {
+                unsafe_ops.push(("raw pointer dereference occurs here", expr.span));
+            },
+
+            ExprKind::Call(path_expr, _) => match path_expr.kind {
+                ExprKind::Path(QPath::Resolved(
+                    _,
+                    hir::Path {
+                        res: Res::Def(kind, def_id),
+                        ..
+                    },
+                )) if kind.is_fn_like() => {
+                    let sig = cx.tcx.fn_sig(*def_id);
+                    if sig.0.unsafety() == Unsafety::Unsafe {
+                        unsafe_ops.push(("unsafe function call occurs here", expr.span));
+                    }
+                },
+
+                ExprKind::Path(QPath::TypeRelative(..)) => {
+                    if let Some(sig) = cx
+                        .typeck_results()
+                        .type_dependent_def_id(path_expr.hir_id)
+                        .map(|def_id| cx.tcx.fn_sig(def_id))
+                    {
+                        if sig.0.unsafety() == Unsafety::Unsafe {
+                            unsafe_ops.push(("unsafe function call occurs here", expr.span));
+                        }
+                    }
+                },
+
+                _ => {},
+            },
+
+            ExprKind::MethodCall(..) => {
+                if let Some(sig) = cx
+                    .typeck_results()
+                    .type_dependent_def_id(expr.hir_id)
+                    .map(|def_id| cx.tcx.fn_sig(def_id))
+                {
+                    if sig.0.unsafety() == Unsafety::Unsafe {
+                        unsafe_ops.push(("unsafe method call occurs here", expr.span));
+                    }
+                }
+            },
+
+            ExprKind::AssignOp(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => {
+                if matches!(
+                    lhs.kind,
+                    ExprKind::Path(QPath::Resolved(
+                        _,
+                        hir::Path {
+                            res: Res::Def(DefKind::Static(Mutability::Mut), _),
+                            ..
+                        }
+                    ))
+                ) {
+                    unsafe_ops.push(("modification of a mutable static occurs here", expr.span));
+                    collect_unsafe_exprs(cx, rhs, unsafe_ops);
+                    return Continue(Descend::No);
+                }
+            },
+
+            _ => {},
+        };
+
+        Continue::<(), _>(Descend::Yes)
+    });
+}
index a651020ca6566341d086bb723d4a85af68c1187e..5f7aac21e6eb00a194ba232c714fb94017e82e5b 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_middle::ty::TypeVisitable;
 use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::sym;
 use std::iter;
@@ -102,21 +103,21 @@ fn check_crate(&mut self, cx: &LateContext<'tcx>) {
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
         if let hir::ItemKind::Fn(ref sig, ..) = item.kind {
-            self.check_sig(cx, item.hir_id(), sig.decl);
+            self.check_sig(cx, item.owner_id.def_id, sig.decl);
         }
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
         if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind {
             if trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
-                self.check_sig(cx, item.hir_id(), sig.decl);
+                self.check_sig(cx, item.owner_id.def_id, sig.decl);
             }
         }
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'tcx>) {
         if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
-            self.check_sig(cx, item.hir_id(), sig.decl);
+            self.check_sig(cx, item.owner_id.def_id, sig.decl);
         }
     }
 
@@ -136,9 +137,8 @@ pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
         }
     }
 
-    fn check_sig(&self, cx: &LateContext<'_>, item_hir_id: hir::HirId, decl: &hir::FnDecl<'_>) {
-        let fn_def_id = cx.tcx.hir().local_def_id(item_hir_id);
-        let fn_sig = cx.tcx.fn_sig(fn_def_id);
+    fn check_sig(&self, cx: &LateContext<'_>, fn_def_id: LocalDefId, decl: &hir::FnDecl<'_>) {
+        let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
         for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
             self.check_ty_(cx, hir_ty.span, *ty);
         }
index 1249db5dc4792307ed353ba64dfd959e8a7368b4..996ea6ed723160d8a7bb31d080059ffab7de6436 100644 (file)
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::{self, TypeVisitable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::kw;
 use rustc_span::{sym, Span};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
-use rustc_trait_selection::traits::misc::can_type_implement_copy;
+use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy;
 use std::borrow::Cow;
 
 declare_clippy_lint! {
@@ -82,12 +83,14 @@ fn check_fn(
         decl: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         span: Span,
-        hir_id: HirId,
+        fn_def_id: LocalDefId,
     ) {
         if span.from_expansion() {
             return;
         }
 
+        let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
+
         match kind {
             FnKind::ItemFn(.., header) => {
                 let attrs = cx.tcx.hir().attrs(hir_id);
@@ -119,8 +122,6 @@ fn check_fn(
 
         let sized_trait = need!(cx.tcx.lang_items().sized_trait());
 
-        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
-
         let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter())
             .filter(|p| !p.is_global())
             .filter_map(|obligation| {
@@ -147,7 +148,7 @@ fn check_fn(
             ctx
         };
 
-        let fn_sig = cx.tcx.fn_sig(fn_def_id);
+        let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
         let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig);
 
         for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() {
@@ -200,7 +201,7 @@ fn check_fn(
                     let sugg = |diag: &mut Diagnostic| {
                         if let ty::Adt(def, ..) = ty.kind() {
                             if let Some(span) = cx.tcx.hir().span_if_local(def.did()) {
-                                if can_type_implement_copy(
+                                if type_allowed_to_implement_copy(
                                     cx.tcx,
                                     cx.param_env,
                                     ty,
index 54a3c82b713daa36684d2da864cbeedc93b5abfc..faf9ec61ec504396d37c9eb076cfe9049d645602 100644 (file)
@@ -75,7 +75,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                     }
                     if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
                         let name = impl_item.ident.name;
-                        let id = impl_item.hir_id();
+                        let id = impl_item.owner_id;
                         if sig.header.constness == hir::Constness::Const {
                             // can't be implemented by default
                             return;
@@ -97,7 +97,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                             if sig.decl.inputs.is_empty();
                             if name == sym::new;
                             if cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id);
-                            let self_def_id = cx.tcx.hir().get_parent_item(id);
+                            let self_def_id = cx.tcx.hir().get_parent_item(id.into());
                             let self_ty = cx.tcx.type_of(self_def_id);
                             if self_ty == return_ty(cx, id);
                             if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
@@ -133,7 +133,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                                 span_lint_hir_and_then(
                                     cx,
                                     NEW_WITHOUT_DEFAULT,
-                                    id,
+                                    id.into(),
                                     impl_item.span,
                                     &format!(
                                         "you should consider adding a `Default` implementation for `{self_type_snip}`"
index 714c0ff227bf829d01f535ea5fc89a944d362b91..839c3a3815c29ef5a55b0bcf877b680916a41923 100644 (file)
@@ -90,7 +90,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             if send_trait == trait_id;
             if hir_impl.polarity == ImplPolarity::Positive;
             if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
-            if let self_ty = ty_trait_ref.self_ty();
+            if let self_ty = ty_trait_ref.subst_identity().self_ty();
             if let ty::Adt(adt_def, impl_trait_substs) = self_ty.kind();
             then {
                 let mut non_send_fields = Vec::new();
index 7722a476d7b4e5182abeea83af939b5653c7bc32..8b77a5c99f767f3edf833e37a5d67429881d696b 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_hir::hir_id::HirIdMap;
 use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
+use rustc_middle::ty::subst::{EarlyBinder, GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, ConstKind};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::{kw, Ident};
@@ -244,7 +244,7 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) {
             })) => {
                 #[allow(trivial_casts)]
                 if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into())
-                    && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+                    && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::subst_identity)
                     && let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id
                 {
                     (
index cff82b875f11a73830cf2ab574593664030ac9f2..d592f6e814c1d3599ceb0dcdac485a729d7d2c6b 100644 (file)
@@ -209,7 +209,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) {
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
         let body_owner = cx.tcx.hir().body_owner(body.id());
-        let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner);
+        let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id());
+
         let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id);
         if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind {
             let body_span = cx.tcx.hir().span_with_body(body_owner);
index 0830a106f55685014b50e19476296bddf8397519..777395f452c92397e47a9caeeee568184e3d6ed6 100644 (file)
@@ -96,7 +96,7 @@ pub fn expr_post(&mut self, id: hir::HirId) {
 
     pub fn enter_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
         let body_owner = cx.tcx.hir().body_owner(body.id());
-        let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner);
+        let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id());
 
         match cx.tcx.hir().body_owner_kind(body_owner_def_id) {
             hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => {
index efec12489a9bad42708568988843610ddfb172b9..849cd03dd7bf639fd8e97d1fe884c16066b6f47e 100644 (file)
@@ -8,6 +8,7 @@
 use rustc_hir::intravisit::FnKind;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
@@ -49,9 +50,13 @@ fn check_fn(
         _: &'tcx hir::FnDecl<'tcx>,
         body: &'tcx hir::Body<'tcx>,
         span: Span,
-        hir_id: hir::HirId,
+        def_id: LocalDefId,
     ) {
-        if !matches!(fn_kind, FnKind::Closure) && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::Result) {
+        if matches!(fn_kind, FnKind::Closure) {
+            return;
+        }
+        let owner = cx.tcx.hir().local_def_id_to_hir_id(def_id).expect_owner();
+        if is_type_diagnostic_item(cx, return_ty(cx, owner), sym::Result) {
             lint_impl_body(cx, span, body);
         }
     }
index 870a1c7d88d532bd6eadbf148acde49fd64b58be..0d78c3048ba127bc2ae74f88b0e7a9c8183f000e 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, Impl, ItemKind, MutTy, Mutability, Node, PatKind};
+use rustc_hir::{BindingAnnotation, Body, FnDecl, Impl, ItemKind, MutTy, Mutability, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, PointerCast};
 use rustc_middle::ty::layout::LayoutOf;
@@ -143,7 +143,7 @@ fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &F
             return;
         }
 
-        let fn_sig = cx.tcx.fn_sig(def_id);
+        let fn_sig = cx.tcx.fn_sig(def_id).subst_identity();
         let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id));
 
         // Gather all the lifetimes found in the output type which may affect whether
@@ -190,10 +190,10 @@ fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &F
                             // Don't lint if an unsafe pointer is created.
                             // TODO: Limit the check only to unsafe pointers to the argument (or part of the argument)
                             //       which escape the current function.
-                            if typeck.node_types().iter().any(|(_, &ty)| ty.is_unsafe_ptr())
+                            if typeck.node_types().items().any(|(_, &ty)| ty.is_unsafe_ptr())
                                 || typeck
                                     .adjustments()
-                                    .iter()
+                                    .items()
                                     .flat_map(|(_, a)| a)
                                     .any(|a| matches!(a.kind, Adjust::Pointer(PointerCast::UnsafeFnPointer)))
                             {
@@ -272,12 +272,13 @@ fn check_fn(
         decl: &'tcx FnDecl<'_>,
         _body: &'tcx Body<'_>,
         span: Span,
-        hir_id: HirId,
+        def_id: LocalDefId,
     ) {
         if span.from_expansion() {
             return;
         }
 
+        let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
         match kind {
             FnKind::ItemFn(.., header) => {
                 if header.abi != Abi::Rust {
@@ -308,6 +309,6 @@ fn check_fn(
             }
         }
 
-        self.check_poly_fn(cx, cx.tcx.hir().local_def_id(hir_id), decl, Some(span));
+        self.check_poly_fn(cx, def_id, decl, Some(span));
     }
 }
index 97b5a4ce36413f4820b209a68f45c3beeb26db54..9f98195d311fed80f3e84e79d64512809bbf1b1f 100644 (file)
@@ -1,11 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::{
-    intravisit, Body, Expr, ExprKind, FnDecl, HirId, Let, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind,
-};
+use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, Let, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 
 declare_clippy_lint! {
@@ -116,7 +115,7 @@ fn check_fn(
         _: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         _: Span,
-        _: HirId,
+        _: LocalDefId,
     ) {
         for param in body.params {
             apply_lint(cx, param.pat, DerefPossible::Impossible);
index 262953042581ab5269cb97221a946830c14059ef..8afe286fbd5dc97d3e42888d9ce22bfdee5f2f37 100644 (file)
@@ -164,7 +164,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
             check_mut_from_ref(cx, sig, None);
             for arg in check_fn_args(
                 cx,
-                cx.tcx.fn_sig(item.owner_id).skip_binder().inputs(),
+                cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder().inputs(),
                 sig.decl.inputs,
                 &[],
             )
@@ -217,7 +217,7 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
 
         check_mut_from_ref(cx, sig, Some(body));
         let decl = sig.decl;
-        let sig = cx.tcx.fn_sig(item_id).skip_binder();
+        let sig = cx.tcx.fn_sig(item_id).subst_identity().skip_binder();
         let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params)
             .filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not)
             .collect();
@@ -624,7 +624,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                             return;
                         };
 
-                        match *self.cx.tcx.fn_sig(id).skip_binder().inputs()[i].peel_refs().kind() {
+                        match *self.cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i].peel_refs().kind() {
                             ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => {
                                 set_skip_flag();
                             },
index c1677fb3da1c4850215dfd6a88e1ee485d4c54ed..944a33cc3e53fad4c0ee3d0fcd9944739fcb76b2 100644 (file)
@@ -6,11 +6,12 @@
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{def_id, Body, FnDecl, HirId, LangItem};
+use rustc_hir::{def_id, Body, FnDecl, LangItem};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::{BytePos, Span};
 use rustc_span::sym;
 
@@ -69,12 +70,10 @@ fn check_fn(
         cx: &LateContext<'tcx>,
         _: FnKind<'tcx>,
         _: &'tcx FnDecl<'_>,
-        body: &'tcx Body<'_>,
+        _: &'tcx Body<'_>,
         _: Span,
-        _: HirId,
+        def_id: LocalDefId,
     ) {
-        let def_id = cx.tcx.hir().body_owner_def_id(body.id());
-
         // Building MIR for `fn`s with unsatisfiable preds results in ICE.
         if fn_has_unsatisfiable_preds(cx, def_id.to_def_id()) {
             return;
index b77faf7322bd00c054a275f4249e844ec9866455..8c39b4fc5691b97735a2a483b16ef2bf98a57510 100644 (file)
@@ -3,7 +3,7 @@
 use clippy_utils::{nth_arg, return_ty};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, FnDecl, HirId, TraitItem, TraitItemKind};
+use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -68,7 +68,7 @@
 
 declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]);
 
-fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, hir_id: HirId) {
+fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, owner_id: OwnerId) {
     if_chain! {
         // If it comes from an external macro, better ignore it.
         if !in_external_macro(cx.sess(), span);
@@ -76,10 +76,10 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa
         // We only show this warning for public exported methods.
         if cx.effective_visibilities.is_exported(fn_def);
         // We don't want to emit this lint if the `#[must_use]` attribute is already there.
-        if !cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::must_use));
+        if !cx.tcx.hir().attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use));
         if cx.tcx.visibility(fn_def.to_def_id()).is_public();
-        let ret_ty = return_ty(cx, hir_id);
-        let self_arg = nth_arg(cx, hir_id, 0);
+        let ret_ty = return_ty(cx, owner_id.into());
+        let self_arg = nth_arg(cx, owner_id.into(), 0);
         // If `Self` has the same type as the returned type, then we want to warn.
         //
         // For this check, we don't want to remove the reference on the returned type because if
@@ -109,26 +109,26 @@ fn check_fn(
         decl: &'tcx FnDecl<'tcx>,
         _: &'tcx Body<'tcx>,
         span: Span,
-        hir_id: HirId,
+        fn_def: LocalDefId,
     ) {
         if_chain! {
             // We are only interested in methods, not in functions or associated functions.
             if matches!(kind, FnKind::Method(_, _));
-            if let Some(fn_def) = cx.tcx.hir().opt_local_def_id(hir_id);
             if let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id());
             // We don't want this method to be te implementation of a trait because the
             // `#[must_use]` should be put on the trait definition directly.
             if cx.tcx.trait_id_of_impl(impl_def).is_none();
 
             then {
-                check_method(cx, decl, fn_def, span, hir_id);
+                let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def);
+                check_method(cx, decl, fn_def, span, hir_id.expect_owner());
             }
         }
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
         if let TraitItemKind::Fn(ref sig, _) = item.kind {
-            check_method(cx, sig.decl, item.owner_id.def_id, item.span, item.hir_id());
+            check_method(cx, sig.decl, item.owner_id.def_id, item.span, item.owner_id);
         }
     }
 }
index bbbd9e4989e97c05f189ddec545cb59d84be67cc..84a0c6b9558531ae41f7116b69d09d8ec4ecd1d6 100644 (file)
@@ -1,16 +1,17 @@
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::source::{snippet_opt, snippet_with_context};
 use clippy_utils::visitors::{for_each_expr, Descend};
-use clippy_utils::{fn_def_id, path_to_local_id};
+use clippy_utils::{fn_def_id, path_to_local_id, span_find_starting_semi};
 use core::ops::ControlFlow;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, LangItem, MatchSource, PatKind, QPath, StmtKind};
+use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, MatchSource, PatKind, QPath, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 use rustc_span::{BytePos, Pos};
 
@@ -151,8 +152,8 @@ fn check_fn(
         kind: FnKind<'tcx>,
         _: &'tcx FnDecl<'tcx>,
         body: &'tcx Body<'tcx>,
-        _: Span,
-        _: HirId,
+        sp: Span,
+        _: LocalDefId,
     ) {
         match kind {
             FnKind::Closure => {
@@ -166,14 +167,14 @@ fn check_fn(
                 check_final_expr(cx, body.value, vec![], replacement);
             },
             FnKind::ItemFn(..) | FnKind::Method(..) => {
-                check_block_return(cx, &body.value.kind, vec![]);
+                check_block_return(cx, &body.value.kind, sp, vec![]);
             },
         }
     }
 }
 
 // if `expr` is a block, check if there are needless returns in it
-fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, semi_spans: Vec<Span>) {
+fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, sp: Span, mut semi_spans: Vec<Span>) {
     if let ExprKind::Block(block, _) = expr_kind {
         if let Some(block_expr) = block.expr {
             check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty);
@@ -183,12 +184,14 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>,
                     check_final_expr(cx, expr, semi_spans, RetReplacement::Empty);
                 },
                 StmtKind::Semi(semi_expr) => {
-                    let mut semi_spans_and_this_one = semi_spans;
-                    // we only want the span containing the semicolon so we can remove it later. From `entry.rs:382`
-                    if let Some(semicolon_span) = stmt.span.trim_start(semi_expr.span) {
-                        semi_spans_and_this_one.push(semicolon_span);
-                        check_final_expr(cx, semi_expr, semi_spans_and_this_one, RetReplacement::Empty);
+                    // Remove ending semicolons and any whitespace ' ' in between.
+                    // Without `return`, the suggestion might not compile if the semicolon is retained
+                    if let Some(semi_span) = stmt.span.trim_start(semi_expr.span) {
+                        let semi_span_to_remove =
+                            span_find_starting_semi(cx.sess().source_map(), semi_span.with_hi(sp.hi()));
+                        semi_spans.push(semi_span_to_remove);
                     }
+                    check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty);
                 },
                 _ => (),
             }
@@ -231,9 +234,9 @@ fn check_final_expr<'tcx>(
             emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement);
         },
         ExprKind::If(_, then, else_clause_opt) => {
-            check_block_return(cx, &then.kind, semi_spans.clone());
+            check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
             if let Some(else_clause) = else_clause_opt {
-                check_block_return(cx, &else_clause.kind, semi_spans);
+                check_block_return(cx, &else_clause.kind, peeled_drop_expr.span, semi_spans);
             }
         },
         // a match expr, check all arms
@@ -246,7 +249,7 @@ fn check_final_expr<'tcx>(
             }
         },
         // if it's a whole block, check it
-        other_expr_kind => check_block_return(cx, other_expr_kind, semi_spans),
+        other_expr_kind => check_block_return(cx, other_expr_kind, peeled_drop_expr.span, semi_spans),
     }
 }
 
@@ -288,6 +291,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
             && cx
                 .tcx
                 .fn_sig(def_id)
+                .subst_identity()
                 .skip_binder()
                 .output()
                 .walk()
index 71b387c66a33084845f4b9adcb8ab930b138f672..3ce030cd721a713491a0db0fd79a1f4f72a045f0 100644 (file)
@@ -54,7 +54,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<
         let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
         let item = cx.tcx.hir().expect_item(parent);
         let self_ty = cx.tcx.type_of(item.owner_id);
-        let ret_ty = return_ty(cx, impl_item.hir_id());
+        let ret_ty = return_ty(cx, impl_item.owner_id);
 
         // Do not check trait impls
         if matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. })) {
index 301aa5798bf556eeeb4bf2389fc671c25c08cbf0..9c0dc8096d0dcc5174699d6a038fef806f5ed667 100644 (file)
@@ -9,7 +9,7 @@
     /// ### What it does
     /// Warns for a Bitwise XOR (`^`) operator being probably confused as a powering. It will not trigger if any of the numbers are not in decimal.
     /// ### Why is this bad?
-    ///        It's most probably a typo and may lead to unexpected behaviours.
+    /// It's most probably a typo and may lead to unexpected behaviours.
     /// ### Example
     /// ```rust
     /// let x = 3_i32 ^ 4_i32;
@@ -18,7 +18,7 @@
     /// ```rust
     /// let x = 3_i32.pow(4);
     /// ```
-    #[clippy::version = "1.66.0"]
+    #[clippy::version = "1.67.0"]
     pub SUSPICIOUS_XOR_USED_AS_POW,
     restriction,
     "XOR (`^`) operator possibly used as exponentiation operator"
index 63b326048a48fe2c1f4322daa6b3d8fe10fbe573..de0c5d56e41566ba89a39c34aad08fe6052283f1 100644 (file)
@@ -61,8 +61,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_
         if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind;
 
         // Then check if that that array zero-sized
-        let length_ldid = cx.tcx.hir().local_def_id(length.hir_id);
-        let length = Const::from_anon_const(cx.tcx, length_ldid);
+        let length = Const::from_anon_const(cx.tcx, length.def_id);
         let length = length.try_eval_usize(cx.tcx, cx.param_env);
         if let Some(length) = length;
         then {
index 691d759d7739dbea81c65ab12c1a12855cda657e..c0d290b5adc420692c0a0e06515283ab3c3ea38f 100644 (file)
@@ -479,7 +479,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 // - char conversions (https://github.com/rust-lang/rust/issues/89259)
                 let const_context = in_constant(cx, e.hir_id);
 
-                let from_ty = cx.typeck_results().expr_ty_adjusted(arg);
+                let (from_ty, from_ty_adjusted) = match cx.typeck_results().expr_adjustments(arg) {
+                    [] => (cx.typeck_results().expr_ty(arg), false),
+                    [.., a] => (a.target, true),
+                };
                 // Adjustments for `to_ty` happen after the call to `transmute`, so don't use them.
                 let to_ty = cx.typeck_results().expr_ty(e);
 
@@ -506,7 +509,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     );
 
                 if !linted {
-                    transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, arg);
+                    transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg);
                 }
             }
         }
index b79d4e915a2718b70ae063b686aa7ad66918ddd0..8530b43243fa36fd6a97c89650cf5f5f0b51d87b 100644 (file)
@@ -1,11 +1,11 @@
-use super::utils::can_be_expressed_as_pointer_cast;
+use super::utils::check_cast;
 use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::sugg;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sugg::Sugg;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{cast::CastKind, Ty};
 
 /// Checks for `transmutes_expressible_as_ptr_casts` lint.
 /// Returns `true` if it's triggered, otherwise returns `false`.
@@ -13,24 +13,40 @@ pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     e: &'tcx Expr<'_>,
     from_ty: Ty<'tcx>,
+    from_ty_adjusted: bool,
     to_ty: Ty<'tcx>,
     arg: &'tcx Expr<'_>,
 ) -> bool {
-    if can_be_expressed_as_pointer_cast(cx, e, from_ty, to_ty) {
-        span_lint_and_then(
-            cx,
-            TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
-            e.span,
-            &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
-            |diag| {
-                if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
-                    let sugg = arg.as_ty(to_ty.to_string()).to_string();
-                    diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
-                }
-            },
-        );
-        true
-    } else {
-        false
-    }
+    use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
+    let mut app = Applicability::MachineApplicable;
+    let sugg = match check_cast(cx, e, from_ty, to_ty) {
+        Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => {
+            Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
+                .as_ty(to_ty.to_string())
+                .to_string()
+        },
+        Some(PtrAddrCast) if !from_ty_adjusted => Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
+            .as_ty(to_ty.to_string())
+            .to_string(),
+
+        // The only adjustments here would be ref-to-ptr and unsize coercions. The result of an unsize coercions can't
+        // be transmuted to a usize. For ref-to-ptr coercions, borrows need to be cast to a pointer before being cast to
+        // a usize.
+        Some(PtrAddrCast) => format!(
+            "{} as {to_ty}",
+            Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app).as_ty(from_ty)
+        ),
+        _ => return false,
+    };
+
+    span_lint_and_sugg(
+        cx,
+        TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
+        e.span,
+        &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
+        "try",
+        sugg,
+        app,
+    );
+    true
 }
index 49d863ec03f1d014c575c776da02a9b3c712d1ba..cddaf9450eabcc4f54d9401371a4330b91a6b3bb 100644 (file)
@@ -20,33 +20,21 @@ pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx
     }
 }
 
-/// Check if the type conversion can be expressed as a pointer cast, instead of
-/// a transmute. In certain cases, including some invalid casts from array
-/// references to pointers, this may cause additional errors to be emitted and/or
-/// ICE error messages. This function will panic if that occurs.
-pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
-    cx: &LateContext<'tcx>,
-    e: &'tcx Expr<'_>,
-    from_ty: Ty<'tcx>,
-    to_ty: Ty<'tcx>,
-) -> bool {
-    use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
-    matches!(
-        check_cast(cx, e, from_ty, to_ty),
-        Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast)
-    )
-}
-
 /// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of
 /// the cast. In certain cases, including some invalid casts from array references
 /// to pointers, this may cause additional errors to be emitted and/or ICE error
 /// messages. This function will panic if that occurs.
-fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> {
+pub(super) fn check_cast<'tcx>(
+    cx: &LateContext<'tcx>,
+    e: &'tcx Expr<'_>,
+    from_ty: Ty<'tcx>,
+    to_ty: Ty<'tcx>,
+) -> Option<CastKind> {
     let hir_id = e.hir_id;
     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 229478b7ce3c9c2b72cf80617fa2f204f3fe38f2..585e2075fa904d0d80549d8b9fe179f9f538ea26 100644 (file)
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    Body, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem,
+    Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem,
     TraitItemKind, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 
 declare_clippy_lint! {
@@ -311,15 +312,27 @@ pub struct Types {
 impl_lint_pass!(Types => [BOX_COLLECTION, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER, RC_MUTEX, TYPE_COMPLEXITY]);
 
 impl<'tcx> LateLintPass<'tcx> for Types {
-    fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
-        let is_in_trait_impl =
-            if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(id).def_id) {
-                matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
-            } else {
-                false
-            };
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'_>,
+        _: FnKind<'_>,
+        decl: &FnDecl<'_>,
+        _: &Body<'_>,
+        _: Span,
+        def_id: LocalDefId,
+    ) {
+        let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(
+            cx.tcx
+                .hir()
+                .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(def_id))
+                .def_id,
+        ) {
+            matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
+        } else {
+            false
+        };
 
-        let is_exported = cx.effective_visibilities.is_exported(cx.tcx.hir().local_def_id(id));
+        let is_exported = cx.effective_visibilities.is_exported(def_id);
 
         self.check_fn_decl(
             cx,
@@ -381,7 +394,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>)
     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
         let is_exported = cx
             .effective_visibilities
-            .is_exported(cx.tcx.hir().local_def_id(field.hir_id));
+            .is_exported(field.def_id);
 
         self.check_ty(
             cx,
index 2e1b6d8d4ea7f743a862d8088ec8554b28ba913d..2920684ade33cd89a98e949da70c3fa8a702694b 100644 (file)
@@ -263,6 +263,18 @@ fn expr_has_unnecessary_safety_comment<'tcx>(
     expr: &'tcx hir::Expr<'tcx>,
     comment_pos: BytePos,
 ) -> Option<Span> {
+    if cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, ref node)| {
+        matches!(
+            node,
+            Node::Block(&Block {
+                rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
+                ..
+            }),
+        )
+    }) {
+        return None;
+    }
+
     // this should roughly be the reverse of `block_parents_have_safety_comment`
     if for_each_expr_with_closures(cx, expr, |expr| match expr.kind {
         hir::ExprKind::Block(
index a138a4baa9b319eb5334709f8ff6089316cb6b9d..289ca4e9bed3cb9707c5fcdea0563a07778c3d6a 100644 (file)
@@ -76,7 +76,7 @@ fn get_projection_pred<'tcx>(
 fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Vec<(usize, String)> {
     let mut args_to_check = Vec::new();
     if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
-        let fn_sig = cx.tcx.fn_sig(def_id);
+        let fn_sig = cx.tcx.fn_sig(def_id).subst_identity();
         let generics = cx.tcx.predicates_of(def_id);
         let fn_mut_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().fn_mut_trait());
         let ord_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.get_diagnostic_item(sym::Ord));
index ce9ebad8c89a85e98687ef486fc410dca262993f..d6167a62169d405fe996fad7007c7d82a410534b 100644 (file)
@@ -156,7 +156,7 @@ fn needs_inferred_result_ty(
         },
         _ => return false,
     };
-    let sig = cx.tcx.fn_sig(id).skip_binder();
+    let sig = cx.tcx.fn_sig(id).subst_identity().skip_binder();
     if let ty::Param(output_ty) = *sig.output().kind() {
         let args: Vec<&Expr<'_>> = if let Some(receiver) = receiver {
             std::iter::once(receiver).chain(args.iter()).collect()
index 84ec0d0fb1cf4ccf42e4bf43e8b4c34f84d192c1..8b0e0ce5a3001581d97c8c9708195e9ae92189ce 100644 (file)
@@ -5,10 +5,11 @@
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::LangItem::{OptionSome, ResultOk};
-use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node};
+use rustc_hir::{Body, ExprKind, FnDecl, Impl, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
@@ -77,12 +78,11 @@ fn check_fn(
         fn_decl: &FnDecl<'tcx>,
         body: &Body<'tcx>,
         span: Span,
-        hir_id: HirId,
+        def_id: LocalDefId,
     ) {
         // Abort if public function/method or closure.
         match fn_kind {
             FnKind::ItemFn(..) | FnKind::Method(..) => {
-                let def_id = cx.tcx.hir().local_def_id(hir_id);
                 if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
                     return;
                 }
@@ -91,6 +91,7 @@ fn check_fn(
         }
 
         // Abort if the method is implementing a trait or of it a trait method.
+        let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
         if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
             if matches!(
                 item.kind,
@@ -101,17 +102,18 @@ fn check_fn(
         }
 
         // Get the wrapper and inner types, if can't, abort.
-        let (return_type_label, lang_item, inner_type) = if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id).kind() {
-            if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) {
-                ("Option", OptionSome, subst.type_at(0))
-            } else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did()) {
-                ("Result", ResultOk, subst.type_at(0))
+        let (return_type_label, lang_item, inner_type) =
+            if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id.expect_owner()).kind() {
+                if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) {
+                    ("Option", OptionSome, subst.type_at(0))
+                } else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did()) {
+                    ("Result", ResultOk, subst.type_at(0))
+                } else {
+                    return;
+                }
             } else {
                 return;
-            }
-        } else {
-            return;
-        };
+            };
 
         // Check if all return expression respect the following condition and collect them.
         let mut suggs = Vec::new();
index 3538bef6e06185a13eb5a17ea1e5a9fb99816a8d..55651a28be9246b660c9f81f7f886c14819ea612 100644 (file)
@@ -1,9 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, YieldSource};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, YieldSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -66,11 +67,11 @@ fn check_fn(
         fn_decl: &'tcx FnDecl<'tcx>,
         body: &Body<'tcx>,
         span: Span,
-        hir_id: HirId,
+        def_id: LocalDefId,
     ) {
         if !span.from_expansion() && fn_kind.asyncness().is_async() {
             let mut visitor = AsyncFnVisitor { cx, found_await: false };
-            walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), hir_id);
+            walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id);
             if !visitor.found_await {
                 span_lint_and_help(
                     cx,
index ea878043c04e3b789e351f99796d55b590d242d3..377d3fb6f4e1ccee8b6e9d9abc53dd571c95cd1e 100644 (file)
@@ -11,6 +11,7 @@
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 use rustc_span::sym;
 
@@ -312,7 +313,7 @@ fn check_fn(
         decl: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         span: Span,
-        fn_id: HirId,
+        fn_id: LocalDefId,
     ) {
         if span.from_expansion() {
             return;
index f3611d174340458fa97177f28b63ddb8ab997b2d..3a1845425a251b12eb0c1f2b4d358282bded6dc8 100644 (file)
@@ -64,8 +64,8 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
             // first check if it's a method or function
             if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind;
             // checking if its return type is `result` or `option`
-            if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::Result)
-                || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::Option);
+            if is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result)
+                || is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Option);
             then {
                 lint_impl_body(cx, impl_item.span, impl_item);
             }
index 4c755d812a0e0fe93c319fc6fa534be220d71022..3cd35838961f65694aa9efce148b114c9b0ee314 100644 (file)
@@ -137,7 +137,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
             then {
                 // `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
                 // `Self`.
-                let self_ty = impl_trait_ref.self_ty();
+                let self_ty = impl_trait_ref.subst_identity().self_ty();
 
                 // `trait_method_sig` is the signature of the function, how it is declared in the
                 // trait, not in the impl of the trait.
@@ -146,7 +146,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
                     .associated_item(impl_item.owner_id)
                     .trait_item_def_id
                     .expect("impl method matches a trait method");
-                let trait_method_sig = cx.tcx.fn_sig(trait_method);
+                let trait_method_sig = cx.tcx.fn_sig(trait_method).subst_identity();
                 let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig);
 
                 // `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
index c1589c771c462f6379ac9e3f16bfd0fb4b86fb08..f48be27592b7e74a1bc3e30a775d70ca142258fa 100644 (file)
@@ -219,7 +219,8 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
     ///
     /// #### Noteworthy
     ///
-    /// A type, say `SomeType`, listed in this configuration has the same behavior of `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
+    /// A type, say `SomeType`, listed in this configuration has the same behavior of
+    /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
     (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
     /// Lint: ARITHMETIC_SIDE_EFFECTS.
     ///
index c4d8c28f0606184bfee6ffd13299833935175681..b1b5164ffb3efbbd8982e7de1595389abc29e17b 100644 (file)
@@ -14,6 +14,7 @@
 use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
 use clippy_utils::{last_path_segment, match_def_path, match_function_call, match_path, paths};
 use if_chain::if_chain;
+use itertools::Itertools;
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{
 use std::path::PathBuf;
 use std::process::Command;
 
-/// This is the output file of the lint collector.
-const OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
+/// This is the json output file of the lint collector.
+const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
+/// This is the markdown output file of the lint collector.
+const MARKDOWN_OUTPUT_FILE: &str = "../book/src/lint_configuration.md";
 /// These lints are excluded from the export.
 const BLACK_LISTED_LINTS: &[&str] = &["lint_author", "dump_hir", "internal_metadata_collector"];
 /// These groups will be ignored by the lint group matcher. This is useful for collections like
@@ -176,6 +179,23 @@ fn get_lint_configs(&self, lint_name: &str) -> Option<String> {
                 )
             })
     }
+
+    fn configs_to_markdown(&self, map_fn: fn(&ClippyConfiguration) -> String) -> String {
+        self.config
+            .iter()
+            .filter(|config| config.deprecation_reason.is_none())
+            .filter(|config| !config.lints.is_empty())
+            .map(map_fn)
+            .join("\n")
+    }
+
+    fn get_markdown_docs(&self) -> String {
+        format!(
+            "## Lint Configuration Options\n| <div style=\"width:290px\">Option</div> | Default Value |\n|--|--|\n{}\n\n{}\n",
+            self.configs_to_markdown(ClippyConfiguration::to_markdown_table_entry),
+            self.configs_to_markdown(ClippyConfiguration::to_markdown_paragraph),
+        )
+    }
 }
 
 impl Drop for MetadataCollector {
@@ -199,12 +219,37 @@ fn drop(&mut self) {
 
         collect_renames(&mut lints);
 
-        // Outputting
-        if Path::new(OUTPUT_FILE).exists() {
-            fs::remove_file(OUTPUT_FILE).unwrap();
+        // Outputting json
+        if Path::new(JSON_OUTPUT_FILE).exists() {
+            fs::remove_file(JSON_OUTPUT_FILE).unwrap();
         }
-        let mut file = OpenOptions::new().write(true).create(true).open(OUTPUT_FILE).unwrap();
+        let mut file = OpenOptions::new()
+            .write(true)
+            .create(true)
+            .open(JSON_OUTPUT_FILE)
+            .unwrap();
         writeln!(file, "{}", serde_json::to_string_pretty(&lints).unwrap()).unwrap();
+
+        // Outputting markdown
+        if Path::new(MARKDOWN_OUTPUT_FILE).exists() {
+            fs::remove_file(MARKDOWN_OUTPUT_FILE).unwrap();
+        }
+        let mut file = OpenOptions::new()
+            .write(true)
+            .create(true)
+            .open(MARKDOWN_OUTPUT_FILE)
+            .unwrap();
+        writeln!(
+            file,
+            "<!--
+This file is generated by `cargo collect-metadata`.
+Please use that command to update the file and do not edit it by hand.
+-->
+
+{}",
+            self.get_markdown_docs(),
+        )
+        .unwrap();
     }
 }
 
@@ -505,6 +550,28 @@ pub fn new(
             deprecation_reason,
         }
     }
+
+    fn to_markdown_paragraph(&self) -> String {
+        format!(
+            "### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n",
+            self.name,
+            self.doc
+                .lines()
+                .map(|line| line.strip_prefix("    ").unwrap_or(line))
+                .join("\n"),
+            self.default,
+            self.config_type,
+            self.lints
+                .iter()
+                .map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
+                .map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
+                .join("\n"),
+        )
+    }
+
+    fn to_markdown_table_entry(&self) -> String {
+        format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default)
+    }
 }
 
 fn collect_configs() -> Vec<ClippyConfiguration> {
index ac6a566b9cd3ae5f208e9c4758a71c79f5867b50..173469f6cdc7d0d3bfa69993153d31ae585d85a9 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.68"
+version = "0.1.69"
 edition = "2021"
 publish = false
 
index 96711936968b5d4ddd1f3f7fb0f3c52d33a69e9f..5c89dd3e49f41569bd2525e90c9a5e58b8ffedf7 100644 (file)
@@ -79,7 +79,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
             && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_)))
         {
             // Limit the function to either `(self) -> bool` or `(&self) -> bool`
-            match &**cx.tcx.fn_sig(fn_id).skip_binder().inputs_and_output {
+            match &**cx.tcx.fn_sig(fn_id).subst_identity().skip_binder().inputs_and_output {
                 [arg, res] if !arg.is_mutable_ptr() && arg.peel_refs() == ty && res.is_bool() => NoChange,
                 _ => Lazy,
             }
index 7a4a9036dd3639ed82de815331ee68897ed37003..26f279f55855f3ef9dd1ca73705acc42f54470d0 100644 (file)
@@ -1,6 +1,5 @@
 #![feature(array_chunks)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(let_chains)]
 #![feature(lint_reasons)]
 #![feature(never_type)]
@@ -1119,9 +1118,8 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                         self.captures.entry(l).and_modify(|e| *e |= cap).or_insert(cap);
                     }
                 },
-                ExprKind::Closure { .. } => {
-                    let closure_id = self.cx.tcx.hir().local_def_id(e.hir_id);
-                    for capture in self.cx.typeck_results().closure_min_captures_flattened(closure_id) {
+                ExprKind::Closure(closure) => {
+                    for capture in self.cx.typeck_results().closure_min_captures_flattened(closure.def_id) {
                         let local_id = match capture.place.base {
                             PlaceBase::Local(id) => id,
                             PlaceBase::Upvar(var) => var.var_path.hir_id,
@@ -1379,7 +1377,7 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
                                     .chain(args.iter())
                                     .position(|arg| arg.hir_id == id)?;
                                 let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
-                                let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
+                                let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i];
                                 ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
                             },
                             _ => None,
@@ -1578,16 +1576,14 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
 }
 
 /// Convenience function to get the return type of a function.
-pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> {
-    let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
-    let ret_ty = cx.tcx.fn_sig(fn_def_id).output();
+pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId) -> Ty<'tcx> {
+    let ret_ty = cx.tcx.fn_sig(fn_def_id).subst_identity().output();
     cx.tcx.erase_late_bound_regions(ret_ty)
 }
 
 /// Convenience function to get the nth argument type of a function.
-pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId, nth: usize) -> Ty<'tcx> {
-    let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
-    let arg = cx.tcx.fn_sig(fn_def_id).input(nth);
+pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId, nth: usize) -> Ty<'tcx> {
+    let arg = cx.tcx.fn_sig(fn_def_id).subst_identity().input(nth);
     cx.tcx.erase_late_bound_regions(arg)
 }
 
@@ -2491,6 +2487,10 @@ pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
     comments_buf.join("\n")
 }
 
+pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
+    sm.span_take_while(span, |&ch| ch == ' ' || ch == ';')
+}
+
 macro_rules! op_utils {
     ($($name:ident $assign:ident)*) => {
         /// Binary operation traits like `LangItem::Add`
index 77c5f1155423c4a7a4399694988e3b56442bae5a..d7f466c1976361bb293a087f657f7478c9537ca5 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;
@@ -328,7 +327,7 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) ->
         } else {
             match cx.tcx.item_name(macro_call.def_id) {
                 // `cfg!(debug_assertions)` in `debug_assert!`
-                sym::cfg => ControlFlow::CONTINUE,
+                sym::cfg => ControlFlow::Continue(()),
                 // assert!(other_macro!(..))
                 _ => ControlFlow::Break(true),
             }
@@ -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
@@ -701,8 +711,8 @@ pub struct FormatSpec<'tcx> {
     pub fill: Option<char>,
     /// Optionally specified alignment.
     pub align: Alignment,
-    /// Packed version of various flags provided, see [`rustc_parse_format::Flag`].
-    pub flags: u32,
+    /// Whether all flag options are set to default (no flags specified).
+    pub no_flags: bool,
     /// Represents either the maximum width or the integer precision.
     pub precision: Count<'tcx>,
     /// The minimum width, will be padded according to `width`/`align`
@@ -718,7 +728,7 @@ fn new(spec: rpf::FormatSpec<'_>, positions: ParamPosition, values: &FormatArgsV
         Some(Self {
             fill: spec.fill,
             align: spec.align,
-            flags: spec.flags,
+            no_flags: spec.sign.is_none() && !spec.alternate && !spec.zero_pad && spec.debug_hex.is_none(),
             precision: Count::new(
                 FormatParamUsage::Precision,
                 spec.precision,
@@ -763,7 +773,7 @@ pub fn is_default_for_trait(&self) -> bool {
         self.width.is_implied()
             && self.precision.is_implied()
             && self.align == Alignment::AlignUnknown
-            && self.flags == 0
+            && self.no_flags
     }
 }
 
@@ -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 9adae7733894580fec10663a47c9ab9a69ebb635..5836eb73bd94c30e2a833250ddd538689a53b7ff 100644 (file)
@@ -140,7 +140,7 @@ impl TypeVisitor<'_> for ContainsRegion {
     type BreakTy = ();
 
     fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow<Self::BreakTy> {
-        ControlFlow::BREAK
+        ControlFlow::Break(())
     }
 }
 
index e5d7da682813c16d4883f2985d0963c03eb03a7c..727058780752e226ce6c06381e30570a5e228325 100644 (file)
@@ -55,7 +55,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
     // impl trait is gone in MIR, so check the return type manually
     check_ty(
         tcx,
-        tcx.fn_sig(def_id).output().skip_binder(),
+        tcx.fn_sig(def_id).subst_identity().output().skip_binder(),
         body.local_decls.iter().next().unwrap().source_info.span,
     )?;
 
@@ -240,6 +240,7 @@ fn check_statement<'tcx>(
         | StatementKind::Retag { .. }
         | StatementKind::AscribeUserType(..)
         | StatementKind::Coverage(..)
+        | StatementKind::ConstEvalCounter
         | StatementKind::Nop => Ok(()),
     }
 }
index e7879bb196e428d3597b88d52d8d30fe83df6414..b8c87aa5e1e423ab02d0593d679afe235f1c4a71 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(..)
@@ -808,7 +809,7 @@ pub struct DerefClosure {
 ///
 /// note: this only works on single line immutable closures with exactly one input parameter.
 pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Option<DerefClosure> {
-    if let hir::ExprKind::Closure(&Closure { fn_decl, body, .. }) = closure.kind {
+    if let hir::ExprKind::Closure(&Closure { fn_decl, def_id, body, .. }) = closure.kind {
         let closure_body = cx.tcx.hir().body(body);
         // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`)
         // a type annotation is present if param `kind` is different from `TyKind::Infer`
@@ -828,10 +829,8 @@ pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Opti
             applicability: Applicability::MachineApplicable,
         };
 
-        let fn_def_id = cx.tcx.hir().local_def_id(closure.hir_id);
         let infcx = cx.tcx.infer_ctxt().build();
-        ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results())
-            .consume_body(closure_body);
+        ExprUseVisitor::new(&mut visitor, &infcx, def_id, cx.param_env, cx.typeck_results()).consume_body(closure_body);
 
         if !visitor.suggestion_start.is_empty() {
             return Some(DerefClosure {
@@ -884,7 +883,7 @@ fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir
                     .cx
                     .typeck_results()
                     .type_dependent_def_id(parent_expr.hir_id)
-                    .map(|did| self.cx.tcx.fn_sig(did).skip_binder())
+                    .map(|did| self.cx.tcx.fn_sig(did).subst_identity().skip_binder())
                 {
                     std::iter::once(receiver)
                         .chain(call_args.iter())
index c8d56a3be5cf356ca7c3723dd8cb29fbed2fbf79..c48d27b05f0459495d73d7d64214380789ca65ac 100644 (file)
@@ -628,7 +628,7 @@ pub fn predicates_id(&self) -> Option<DefId> {
 /// If the expression is function like, get the signature for it.
 pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> {
     if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) {
-        Some(ExprFnSig::Sig(cx.tcx.fn_sig(id), Some(id)))
+        Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst_identity(), Some(id)))
     } else {
         ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs())
     }
@@ -646,10 +646,13 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
                 .and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id)));
             Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
         },
-        ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
-        ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
-            sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id))
-        },
+        ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst(cx.tcx, subs), Some(id))),
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => sig_from_bounds(
+            cx,
+            ty,
+            cx.tcx.item_bounds(def_id).subst(cx.tcx, substs),
+            cx.tcx.opt_parent(def_id),
+        ),
         ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
         ty::Dynamic(bounds, _, _) => {
             let lang_items = cx.tcx.lang_items();
index 14c01a60b4c32b775e7aa5cce1ce9a242b363fd7..d18b62d1bf16aef6ac7cc3ee85c13d5035d8fdd7 100644 (file)
@@ -392,12 +392,12 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                         .cx
                         .typeck_results()
                         .type_dependent_def_id(e.hir_id)
-                        .map_or(false, |id| self.cx.tcx.fn_sig(id).unsafety() == Unsafety::Unsafe) =>
+                        .map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe) =>
                 {
                     self.is_unsafe = true;
                 },
                 ExprKind::Call(func, _) => match *self.cx.typeck_results().expr_ty(func).peel_refs().kind() {
-                    ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
+                    ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
                     ty::FnPtr(sig) if sig.unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
                     _ => walk_expr(self, e),
                 },
index c01e1062cb5445c2557a08692ff35eb79212db2d..80eee368178e1418f1ea534a64610e73231422e0 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "declare_clippy_lint"
-version = "0.1.68"
+version = "0.1.69"
 edition = "2021"
 publish = false
 
index 40a6f47095ec2e59705f4f889ff1250a5af7065d..4e7fc565a322ae55c12f271fea5e65633830a0f8 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-01-12"
+channel = "nightly-2023-01-27"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
index 7a78b32620d0bf41301fa50cf781b6a5c658bb45..82147eba33f07ac77931498c4c3f782cce896f8b 100644 (file)
@@ -28,7 +28,7 @@
     -D --deny OPT       Set lint denied
     -F --forbid OPT     Set lint forbidden
 
-You can use tool lints to allow or deny lints from your code, eg.:
+You can use tool lints to allow or deny lints from your code, e.g.:
 
     #[allow(clippy::needless_lifetimes)]
 "#;
index 3ca45404e44bb88290ad846bccca89f21b88f6a7..2a240cc249b0c768f084dab5b6f220ae53a59399 100644 (file)
@@ -7,14 +7,6 @@ LL |     const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
    = help: convert all references to use `sym::Deref`
    = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
 
-error: hardcoded path to a language item
-  --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
-   |
-LL |     const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: convert all references to use `LangItem::DerefMut`
-
 error: hardcoded path to a diagnostic item
   --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
    |
@@ -23,5 +15,13 @@ LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref",
    |
    = help: convert all references to use `sym::deref_method`
 
+error: hardcoded path to a language item
+  --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
+   |
+LL |     const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: convert all references to use `LangItem::DerefMut`
+
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.fixed b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed
new file mode 100644 (file)
index 0000000..95f35a6
--- /dev/null
@@ -0,0 +1,161 @@
+// run-rustfix
+
+#![allow(unused, clippy::assertions_on_constants)]
+#![warn(clippy::bool_assert_comparison)]
+
+use std::ops::Not;
+
+macro_rules! a {
+    () => {
+        true
+    };
+}
+macro_rules! b {
+    () => {
+        true
+    };
+}
+
+// Implements the Not trait but with an output type
+// that's not bool. Should not suggest a rewrite
+#[derive(Debug, Clone, Copy)]
+enum ImplNotTraitWithoutBool {
+    VariantX(bool),
+    VariantY(u32),
+}
+
+impl PartialEq<bool> for ImplNotTraitWithoutBool {
+    fn eq(&self, other: &bool) -> bool {
+        match *self {
+            ImplNotTraitWithoutBool::VariantX(b) => b == *other,
+            _ => false,
+        }
+    }
+}
+
+impl Not for ImplNotTraitWithoutBool {
+    type Output = Self;
+
+    fn not(self) -> Self::Output {
+        match self {
+            ImplNotTraitWithoutBool::VariantX(b) => ImplNotTraitWithoutBool::VariantX(!b),
+            ImplNotTraitWithoutBool::VariantY(0) => ImplNotTraitWithoutBool::VariantY(1),
+            ImplNotTraitWithoutBool::VariantY(_) => ImplNotTraitWithoutBool::VariantY(0),
+        }
+    }
+}
+
+// This type implements the Not trait with an Output of
+// type bool. Using assert!(..) must be suggested
+#[derive(Debug, Clone, Copy)]
+struct ImplNotTraitWithBool;
+
+impl PartialEq<bool> for ImplNotTraitWithBool {
+    fn eq(&self, other: &bool) -> bool {
+        false
+    }
+}
+
+impl Not for ImplNotTraitWithBool {
+    type Output = bool;
+
+    fn not(self) -> Self::Output {
+        true
+    }
+}
+
+#[derive(Debug)]
+struct NonCopy;
+
+impl PartialEq<bool> for NonCopy {
+    fn eq(&self, other: &bool) -> bool {
+        false
+    }
+}
+
+impl Not for NonCopy {
+    type Output = bool;
+
+    fn not(self) -> Self::Output {
+        true
+    }
+}
+
+fn main() {
+    let a = ImplNotTraitWithoutBool::VariantX(true);
+    let b = ImplNotTraitWithBool;
+
+    assert_eq!("a".len(), 1);
+    assert!("a".is_empty());
+    assert!("".is_empty());
+    assert!("".is_empty());
+    assert_eq!(a!(), b!());
+    assert_eq!(a!(), "".is_empty());
+    assert_eq!("".is_empty(), b!());
+    assert_eq!(a, true);
+    assert!(b);
+
+    assert_ne!("a".len(), 1);
+    assert!("a".is_empty());
+    assert!("".is_empty());
+    assert!("".is_empty());
+    assert_ne!(a!(), b!());
+    assert_ne!(a!(), "".is_empty());
+    assert_ne!("".is_empty(), b!());
+    assert_ne!(a, true);
+    assert!(b);
+
+    debug_assert_eq!("a".len(), 1);
+    debug_assert!("a".is_empty());
+    debug_assert!("".is_empty());
+    debug_assert!("".is_empty());
+    debug_assert_eq!(a!(), b!());
+    debug_assert_eq!(a!(), "".is_empty());
+    debug_assert_eq!("".is_empty(), b!());
+    debug_assert_eq!(a, true);
+    debug_assert!(b);
+
+    debug_assert_ne!("a".len(), 1);
+    debug_assert!("a".is_empty());
+    debug_assert!("".is_empty());
+    debug_assert!("".is_empty());
+    debug_assert_ne!(a!(), b!());
+    debug_assert_ne!(a!(), "".is_empty());
+    debug_assert_ne!("".is_empty(), b!());
+    debug_assert_ne!(a, true);
+    debug_assert!(b);
+
+    // assert with error messages
+    assert_eq!("a".len(), 1, "tadam {}", 1);
+    assert_eq!("a".len(), 1, "tadam {}", true);
+    assert!("a".is_empty(), "tadam {}", 1);
+    assert!("a".is_empty(), "tadam {}", true);
+    assert!("a".is_empty(), "tadam {}", true);
+    assert_eq!(a, true, "tadam {}", false);
+
+    debug_assert_eq!("a".len(), 1, "tadam {}", 1);
+    debug_assert_eq!("a".len(), 1, "tadam {}", true);
+    debug_assert!("a".is_empty(), "tadam {}", 1);
+    debug_assert!("a".is_empty(), "tadam {}", true);
+    debug_assert!("a".is_empty(), "tadam {}", true);
+    debug_assert_eq!(a, true, "tadam {}", false);
+
+    assert!(a!());
+    assert!(b!());
+
+    use debug_assert_eq as renamed;
+    renamed!(a, true);
+    debug_assert!(b);
+
+    let non_copy = NonCopy;
+    assert_eq!(non_copy, true);
+    // changing the above to `assert!(non_copy)` would cause a `borrow of moved value`
+    println!("{non_copy:?}");
+
+    macro_rules! in_macro {
+        ($v:expr) => {{
+            assert_eq!($v, true);
+        }};
+    }
+    in_macro!(a);
+}
index ec4d6f3ff840113829343f89f7ff45f2d9e45f8b..88e7560b4f984ba863186e7695c482384d21015a 100644 (file)
@@ -1,3 +1,6 @@
+// run-rustfix
+
+#![allow(unused, clippy::assertions_on_constants)]
 #![warn(clippy::bool_assert_comparison)]
 
 use std::ops::Not;
@@ -15,7 +18,7 @@ macro_rules! b {
 
 // Implements the Not trait but with an output type
 // that's not bool. Should not suggest a rewrite
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
 enum ImplNotTraitWithoutBool {
     VariantX(bool),
     VariantY(u32),
@@ -44,7 +47,7 @@ fn not(self) -> Self::Output {
 
 // This type implements the Not trait with an Output of
 // type bool. Using assert!(..) must be suggested
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
 struct ImplNotTraitWithBool;
 
 impl PartialEq<bool> for ImplNotTraitWithBool {
@@ -61,6 +64,23 @@ fn not(self) -> Self::Output {
     }
 }
 
+#[derive(Debug)]
+struct NonCopy;
+
+impl PartialEq<bool> for NonCopy {
+    fn eq(&self, other: &bool) -> bool {
+        false
+    }
+}
+
+impl Not for NonCopy {
+    type Output = bool;
+
+    fn not(self) -> Self::Output {
+        true
+    }
+}
+
 fn main() {
     let a = ImplNotTraitWithoutBool::VariantX(true);
     let b = ImplNotTraitWithBool;
@@ -119,4 +139,23 @@ fn main() {
     debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
     debug_assert_eq!(false, "a".is_empty(), "tadam {}", true);
     debug_assert_eq!(a, true, "tadam {}", false);
+
+    assert_eq!(a!(), true);
+    assert_eq!(true, b!());
+
+    use debug_assert_eq as renamed;
+    renamed!(a, true);
+    renamed!(b, true);
+
+    let non_copy = NonCopy;
+    assert_eq!(non_copy, true);
+    // changing the above to `assert!(non_copy)` would cause a `borrow of moved value`
+    println!("{non_copy:?}");
+
+    macro_rules! in_macro {
+        ($v:expr) => {{
+            assert_eq!($v, true);
+        }};
+    }
+    in_macro!(a);
 }
index 377d51be4cde7438cad96c7e5b6cd583a0f3dfbe..3d9f8573e617c8f93d3af887c7063511af82a814 100644 (file)
 error: used `assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:69:5
+  --> $DIR/bool_assert_comparison.rs:89:5
    |
 LL |     assert_eq!("a".is_empty(), false);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::bool-assert-comparison` implied by `-D warnings`
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!("a".is_empty(), false);
+LL +     assert!("a".is_empty());
+   |
 
 error: used `assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:70:5
+  --> $DIR/bool_assert_comparison.rs:90:5
    |
 LL |     assert_eq!("".is_empty(), true);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!("".is_empty(), true);
+LL +     assert!("".is_empty());
+   |
 
 error: used `assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:71:5
+  --> $DIR/bool_assert_comparison.rs:91:5
    |
 LL |     assert_eq!(true, "".is_empty());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!(true, "".is_empty());
+LL +     assert!("".is_empty());
+   |
 
 error: used `assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:76:5
+  --> $DIR/bool_assert_comparison.rs:96:5
    |
 LL |     assert_eq!(b, true);
-   |     ^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!(b, true);
+LL +     assert!(b);
+   |
 
 error: used `assert_ne!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:79:5
+  --> $DIR/bool_assert_comparison.rs:99:5
    |
 LL |     assert_ne!("a".is_empty(), false);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_ne!("a".is_empty(), false);
+LL +     assert!("a".is_empty());
+   |
 
 error: used `assert_ne!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:80:5
+  --> $DIR/bool_assert_comparison.rs:100:5
    |
 LL |     assert_ne!("".is_empty(), true);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_ne!("".is_empty(), true);
+LL +     assert!("".is_empty());
+   |
 
 error: used `assert_ne!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:81:5
+  --> $DIR/bool_assert_comparison.rs:101:5
    |
 LL |     assert_ne!(true, "".is_empty());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_ne!(true, "".is_empty());
+LL +     assert!("".is_empty());
+   |
 
 error: used `assert_ne!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:86:5
+  --> $DIR/bool_assert_comparison.rs:106:5
    |
 LL |     assert_ne!(b, true);
-   |     ^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_ne!(b, true);
+LL +     assert!(b);
+   |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:89:5
+  --> $DIR/bool_assert_comparison.rs:109:5
    |
 LL |     debug_assert_eq!("a".is_empty(), false);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_eq!("a".is_empty(), false);
+LL +     debug_assert!("a".is_empty());
+   |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:90:5
+  --> $DIR/bool_assert_comparison.rs:110:5
    |
 LL |     debug_assert_eq!("".is_empty(), true);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_eq!("".is_empty(), true);
+LL +     debug_assert!("".is_empty());
+   |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:91:5
+  --> $DIR/bool_assert_comparison.rs:111:5
    |
 LL |     debug_assert_eq!(true, "".is_empty());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_eq!(true, "".is_empty());
+LL +     debug_assert!("".is_empty());
+   |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:96:5
+  --> $DIR/bool_assert_comparison.rs:116:5
    |
 LL |     debug_assert_eq!(b, true);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_eq!(b, true);
+LL +     debug_assert!(b);
+   |
 
 error: used `debug_assert_ne!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:99:5
+  --> $DIR/bool_assert_comparison.rs:119:5
    |
 LL |     debug_assert_ne!("a".is_empty(), false);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_ne!("a".is_empty(), false);
+LL +     debug_assert!("a".is_empty());
+   |
 
 error: used `debug_assert_ne!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:100:5
+  --> $DIR/bool_assert_comparison.rs:120:5
    |
 LL |     debug_assert_ne!("".is_empty(), true);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_ne!("".is_empty(), true);
+LL +     debug_assert!("".is_empty());
+   |
 
 error: used `debug_assert_ne!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:101:5
+  --> $DIR/bool_assert_comparison.rs:121:5
    |
 LL |     debug_assert_ne!(true, "".is_empty());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_ne!(true, "".is_empty());
+LL +     debug_assert!("".is_empty());
+   |
 
 error: used `debug_assert_ne!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:106:5
+  --> $DIR/bool_assert_comparison.rs:126:5
    |
 LL |     debug_assert_ne!(b, true);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_ne!(b, true);
+LL +     debug_assert!(b);
+   |
 
 error: used `assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:111:5
+  --> $DIR/bool_assert_comparison.rs:131:5
    |
 LL |     assert_eq!("a".is_empty(), false, "tadam {}", 1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!("a".is_empty(), false, "tadam {}", 1);
+LL +     assert!("a".is_empty(), "tadam {}", 1);
+   |
 
 error: used `assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:112:5
+  --> $DIR/bool_assert_comparison.rs:132:5
    |
 LL |     assert_eq!("a".is_empty(), false, "tadam {}", true);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!("a".is_empty(), false, "tadam {}", true);
+LL +     assert!("a".is_empty(), "tadam {}", true);
+   |
 
 error: used `assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:113:5
+  --> $DIR/bool_assert_comparison.rs:133:5
    |
 LL |     assert_eq!(false, "a".is_empty(), "tadam {}", true);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!(false, "a".is_empty(), "tadam {}", true);
+LL +     assert!("a".is_empty(), "tadam {}", true);
+   |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:118:5
+  --> $DIR/bool_assert_comparison.rs:138:5
    |
 LL |     debug_assert_eq!("a".is_empty(), false, "tadam {}", 1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_eq!("a".is_empty(), false, "tadam {}", 1);
+LL +     debug_assert!("a".is_empty(), "tadam {}", 1);
+   |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:119:5
+  --> $DIR/bool_assert_comparison.rs:139:5
    |
 LL |     debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
+LL +     debug_assert!("a".is_empty(), "tadam {}", true);
+   |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> $DIR/bool_assert_comparison.rs:120:5
+  --> $DIR/bool_assert_comparison.rs:140:5
    |
 LL |     debug_assert_eq!(false, "a".is_empty(), "tadam {}", true);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_eq!(false, "a".is_empty(), "tadam {}", true);
+LL +     debug_assert!("a".is_empty(), "tadam {}", true);
+   |
+
+error: used `assert_eq!` with a literal bool
+  --> $DIR/bool_assert_comparison.rs:143:5
+   |
+LL |     assert_eq!(a!(), true);
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!(a!(), true);
+LL +     assert!(a!());
+   |
+
+error: used `assert_eq!` with a literal bool
+  --> $DIR/bool_assert_comparison.rs:144:5
+   |
+LL |     assert_eq!(true, b!());
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!(true, b!());
+LL +     assert!(b!());
+   |
+
+error: used `debug_assert_eq!` with a literal bool
+  --> $DIR/bool_assert_comparison.rs:148:5
+   |
+LL |     renamed!(b, true);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     renamed!(b, true);
+LL +     debug_assert!(b);
+   |
 
-error: aborting due to 22 previous errors
+error: aborting due to 25 previous errors
 
index e6031e9adaeb66c084d8c96cb421d9d5ee186d91..8b2673c2a7fdb24f15e267a76123e4284e279696 100644 (file)
@@ -28,6 +28,7 @@ fn main() {
     1i32 as u8;
     1f64 as isize;
     1f64 as usize;
+    1f32 as u32 as u16;
     // Test clippy::cast_possible_wrap
     1u8 as i8;
     1u16 as i16;
index 0c63b4af30865da871c4d9b241fd9f6d9dc979aa..4af1de9aa38d354db9afdbad5172a63f7fa9132b 100644 (file)
@@ -42,13 +42,24 @@ error: casting `f32` to `i32` may truncate the value
 LL |     1f32 as i32;
    |     ^^^^^^^^^^^
    |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
    = note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     i32::try_from(1f32);
+   |     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `f32` to `u32` may truncate the value
   --> $DIR/cast.rs:25:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     u32::try_from(1f32);
+   |     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `f32` to `u32` may lose the sign of the value
   --> $DIR/cast.rs:25:5
@@ -63,30 +74,60 @@ error: casting `f64` to `f32` may truncate the value
    |
 LL |     1f64 as f32;
    |     ^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     f32::try_from(1f64);
+   |     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `i8` may truncate the value
   --> $DIR/cast.rs:27:5
    |
 LL |     1i32 as i8;
    |     ^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     i8::try_from(1i32);
+   |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `u8` may truncate the value
   --> $DIR/cast.rs:28:5
    |
 LL |     1i32 as u8;
    |     ^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     u8::try_from(1i32);
+   |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `f64` to `isize` may truncate the value
   --> $DIR/cast.rs:29:5
    |
 LL |     1f64 as isize;
    |     ^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     isize::try_from(1f64);
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `f64` to `usize` may truncate the value
   --> $DIR/cast.rs:30:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     usize::try_from(1f64);
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `f64` to `usize` may lose the sign of the value
   --> $DIR/cast.rs:30:5
@@ -94,8 +135,38 @@ error: casting `f64` to `usize` may lose the sign of the value
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
 
+error: casting `u32` to `u16` may truncate the value
+  --> $DIR/cast.rs:31:5
+   |
+LL |     1f32 as u32 as u16;
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     u16::try_from(1f32 as u32);
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: casting `f32` to `u32` may truncate the value
+  --> $DIR/cast.rs:31:5
+   |
+LL |     1f32 as u32 as u16;
+   |     ^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     u32::try_from(1f32) as u16;
+   |     ~~~~~~~~~~~~~~~~~~~
+
+error: casting `f32` to `u32` may lose the sign of the value
+  --> $DIR/cast.rs:31:5
+   |
+LL |     1f32 as u32 as u16;
+   |     ^^^^^^^^^^^
+
 error: casting `u8` to `i8` may wrap around the value
-  --> $DIR/cast.rs:32:5
+  --> $DIR/cast.rs:33:5
    |
 LL |     1u8 as i8;
    |     ^^^^^^^^^
@@ -103,61 +174,79 @@ LL |     1u8 as i8;
    = note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
 
 error: casting `u16` to `i16` may wrap around the value
-  --> $DIR/cast.rs:33:5
+  --> $DIR/cast.rs:34:5
    |
 LL |     1u16 as i16;
    |     ^^^^^^^^^^^
 
 error: casting `u32` to `i32` may wrap around the value
-  --> $DIR/cast.rs:34:5
+  --> $DIR/cast.rs:35:5
    |
 LL |     1u32 as i32;
    |     ^^^^^^^^^^^
 
 error: casting `u64` to `i64` may wrap around the value
-  --> $DIR/cast.rs:35:5
+  --> $DIR/cast.rs:36:5
    |
 LL |     1u64 as i64;
    |     ^^^^^^^^^^^
 
 error: casting `usize` to `isize` may wrap around the value
-  --> $DIR/cast.rs:36:5
+  --> $DIR/cast.rs:37:5
    |
 LL |     1usize as isize;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> $DIR/cast.rs:39:5
+  --> $DIR/cast.rs:40:5
    |
 LL |     -1i32 as u32;
    |     ^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> $DIR/cast.rs:41:5
+  --> $DIR/cast.rs:42:5
    |
 LL |     -1isize as usize;
    |     ^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `i8` may truncate the value
-  --> $DIR/cast.rs:108:5
+  --> $DIR/cast.rs:109:5
    |
 LL |     (-99999999999i64).min(1) as i8; // should be linted because signed
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     i8::try_from((-99999999999i64).min(1)); // should be linted because signed
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `u8` may truncate the value
-  --> $DIR/cast.rs:120:5
+  --> $DIR/cast.rs:121:5
    |
 LL |     999999u64.clamp(0, 256) as u8; // should still be linted
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     u8::try_from(999999u64.clamp(0, 256)); // should still be linted
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2` to `u8` may truncate the value
-  --> $DIR/cast.rs:141:21
+  --> $DIR/cast.rs:142:21
    |
 LL |             let _ = self as u8;
    |                     ^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |             let _ = u8::try_from(self);
+   |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2::B` to `u8` will truncate the value
-  --> $DIR/cast.rs:142:21
+  --> $DIR/cast.rs:143:21
    |
 LL |             let _ = Self::B as u8;
    |                     ^^^^^^^^^^^^^
@@ -165,46 +254,82 @@ LL |             let _ = Self::B as u8;
    = note: `-D clippy::cast-enum-truncation` implied by `-D warnings`
 
 error: casting `main::E5` to `i8` may truncate the value
-  --> $DIR/cast.rs:178:21
+  --> $DIR/cast.rs:179:21
    |
 LL |             let _ = self as i8;
    |                     ^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |             let _ = i8::try_from(self);
+   |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E5::A` to `i8` will truncate the value
-  --> $DIR/cast.rs:179:21
+  --> $DIR/cast.rs:180:21
    |
 LL |             let _ = Self::A as i8;
    |                     ^^^^^^^^^^^^^
 
 error: casting `main::E6` to `i16` may truncate the value
-  --> $DIR/cast.rs:193:21
+  --> $DIR/cast.rs:194:21
    |
 LL |             let _ = self as i16;
    |                     ^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |             let _ = i16::try_from(self);
+   |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> $DIR/cast.rs:208:21
+  --> $DIR/cast.rs:209:21
    |
 LL |             let _ = self as usize;
    |                     ^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |             let _ = usize::try_from(self);
+   |                     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E10` to `u16` may truncate the value
-  --> $DIR/cast.rs:249:21
+  --> $DIR/cast.rs:250:21
    |
 LL |             let _ = self as u16;
    |                     ^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |             let _ = u16::try_from(self);
+   |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> $DIR/cast.rs:257:13
+  --> $DIR/cast.rs:258:13
    |
 LL |     let c = (q >> 16) as u8;
    |             ^^^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     let c = u8::try_from((q >> 16));
+   |             ~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> $DIR/cast.rs:260:13
+  --> $DIR/cast.rs:261:13
    |
 LL |     let c = (q / 1000) as u8;
    |             ^^^^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     let c = u8::try_from((q / 1000));
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~
 
-error: aborting due to 33 previous errors
+error: aborting due to 36 previous errors
 
index 95552f2e285396dd05db7fb3b6993d9113ee408c..8acf26049f4d15755f9163ed6b0836a59c436e8b 100644 (file)
@@ -4,7 +4,12 @@ error: casting `isize` to `i8` may truncate the value
 LL |     1isize as i8;
    |     ^^^^^^^^^^^^
    |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
    = note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     i8::try_from(1isize);
+   |     ~~~~~~~~~~~~~~~~~~~~
 
 error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
   --> $DIR/cast_size.rs:15:5
@@ -37,24 +42,48 @@ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wi
    |
 LL |     1isize as i32;
    |     ^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     i32::try_from(1isize);
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers
   --> $DIR/cast_size.rs:20:5
    |
 LL |     1isize as u32;
    |     ^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     u32::try_from(1isize);
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers
   --> $DIR/cast_size.rs:21:5
    |
 LL |     1usize as u32;
    |     ^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     u32::try_from(1usize);
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
   --> $DIR/cast_size.rs:22:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     i32::try_from(1usize);
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
   --> $DIR/cast_size.rs:22:5
@@ -69,18 +98,36 @@ error: casting `i64` to `isize` may truncate the value on targets with 32-bit wi
    |
 LL |     1i64 as isize;
    |     ^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     isize::try_from(1i64);
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
   --> $DIR/cast_size.rs:25:5
    |
 LL |     1i64 as usize;
    |     ^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     usize::try_from(1i64);
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
   --> $DIR/cast_size.rs:26:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     isize::try_from(1u64);
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
   --> $DIR/cast_size.rs:26:5
@@ -93,6 +140,12 @@ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wi
    |
 LL |     1u64 as usize;
    |     ^^^^^^^^^^^^^
+   |
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+help: ... or use `try_from` and handle the error accordingly
+   |
+LL |     usize::try_from(1u64);
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
   --> $DIR/cast_size.rs:28:5
index 3f343a3e430185f8ca8535370c363b1f2c308ace..277801194a1d5d1d37a328e8236b7ba9db2e9e59 100644 (file)
@@ -1,34 +1,34 @@
 error: item name starts with its containing module's name
-  --> $DIR/module_name_repetitions.rs:8:5
+  --> $DIR/module_name_repetitions.rs:8:12
    |
 LL |     pub fn foo_bar() {}
-   |     ^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^
    |
    = note: `-D clippy::module-name-repetitions` implied by `-D warnings`
 
 error: item name ends with its containing module's name
-  --> $DIR/module_name_repetitions.rs:9:5
+  --> $DIR/module_name_repetitions.rs:9:12
    |
 LL |     pub fn bar_foo() {}
-   |     ^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^
 
 error: item name starts with its containing module's name
-  --> $DIR/module_name_repetitions.rs:10:5
+  --> $DIR/module_name_repetitions.rs:10:16
    |
 LL |     pub struct FooCake;
-   |     ^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^
 
 error: item name ends with its containing module's name
-  --> $DIR/module_name_repetitions.rs:11:5
+  --> $DIR/module_name_repetitions.rs:11:14
    |
 LL |     pub enum CakeFoo {}
-   |     ^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^
 
 error: item name starts with its containing module's name
-  --> $DIR/module_name_repetitions.rs:12:5
+  --> $DIR/module_name_repetitions.rs:12:16
    |
 LL |     pub struct Foo7Bar;
-   |     ^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^
 
 error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
new file mode 100644 (file)
index 0000000..4126353
--- /dev/null
@@ -0,0 +1,110 @@
+#![allow(unused)]
+#![allow(deref_nullptr)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(clippy::drop_copy)]
+#![warn(clippy::multiple_unsafe_ops_per_block)]
+
+use core::arch::asm;
+
+fn raw_ptr() -> *const () {
+    core::ptr::null()
+}
+
+unsafe fn not_very_safe() {}
+
+struct Sample;
+
+impl Sample {
+    unsafe fn not_very_safe(&self) {}
+}
+
+#[allow(non_upper_case_globals)]
+const sample: Sample = Sample;
+
+union U {
+    i: i32,
+    u: u32,
+}
+
+static mut STATIC: i32 = 0;
+
+fn test1() {
+    unsafe {
+        STATIC += 1;
+        not_very_safe();
+    }
+}
+
+fn test2() {
+    let u = U { i: 0 };
+
+    unsafe {
+        drop(u.u);
+        *raw_ptr();
+    }
+}
+
+fn test3() {
+    unsafe {
+        asm!("nop");
+        sample.not_very_safe();
+        STATIC = 0;
+    }
+}
+
+fn test_all() {
+    let u = U { i: 0 };
+    unsafe {
+        drop(u.u);
+        drop(STATIC);
+        sample.not_very_safe();
+        not_very_safe();
+        *raw_ptr();
+        asm!("nop");
+    }
+}
+
+// no lint
+fn correct1() {
+    unsafe {
+        STATIC += 1;
+    }
+}
+
+// no lint
+fn correct2() {
+    unsafe {
+        STATIC += 1;
+    }
+
+    unsafe {
+        *raw_ptr();
+    }
+}
+
+// no lint
+fn correct3() {
+    let u = U { u: 0 };
+
+    unsafe {
+        not_very_safe();
+    }
+
+    unsafe {
+        drop(u.i);
+    }
+}
+
+// tests from the issue (https://github.com/rust-lang/rust-clippy/issues/10064)
+
+unsafe fn read_char_bad(ptr: *const u8) -> char {
+    unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+}
+
+// no lint
+unsafe fn read_char_good(ptr: *const u8) -> char {
+    let int_value = unsafe { *ptr.cast::<u32>() };
+    unsafe { core::char::from_u32_unchecked(int_value) }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr
new file mode 100644 (file)
index 0000000..f6b8341
--- /dev/null
@@ -0,0 +1,129 @@
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+  --> $DIR/multiple_unsafe_ops_per_block.rs:32:5
+   |
+LL | /     unsafe {
+LL | |         STATIC += 1;
+LL | |         not_very_safe();
+LL | |     }
+   | |_____^
+   |
+note: modification of a mutable static occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:33:9
+   |
+LL |         STATIC += 1;
+   |         ^^^^^^^^^^^
+note: unsafe function call occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:34:9
+   |
+LL |         not_very_safe();
+   |         ^^^^^^^^^^^^^^^
+   = note: `-D clippy::multiple-unsafe-ops-per-block` implied by `-D warnings`
+
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+  --> $DIR/multiple_unsafe_ops_per_block.rs:41:5
+   |
+LL | /     unsafe {
+LL | |         drop(u.u);
+LL | |         *raw_ptr();
+LL | |     }
+   | |_____^
+   |
+note: union field access occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:42:14
+   |
+LL |         drop(u.u);
+   |              ^^^
+note: raw pointer dereference occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:43:9
+   |
+LL |         *raw_ptr();
+   |         ^^^^^^^^^^
+
+error: this `unsafe` block contains 3 unsafe operations, expected only one
+  --> $DIR/multiple_unsafe_ops_per_block.rs:48:5
+   |
+LL | /     unsafe {
+LL | |         asm!("nop");
+LL | |         sample.not_very_safe();
+LL | |         STATIC = 0;
+LL | |     }
+   | |_____^
+   |
+note: inline assembly used here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:49:9
+   |
+LL |         asm!("nop");
+   |         ^^^^^^^^^^^
+note: unsafe method call occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:50:9
+   |
+LL |         sample.not_very_safe();
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+note: modification of a mutable static occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:51:9
+   |
+LL |         STATIC = 0;
+   |         ^^^^^^^^^^
+
+error: this `unsafe` block contains 6 unsafe operations, expected only one
+  --> $DIR/multiple_unsafe_ops_per_block.rs:57:5
+   |
+LL | /     unsafe {
+LL | |         drop(u.u);
+LL | |         drop(STATIC);
+LL | |         sample.not_very_safe();
+...  |
+LL | |         asm!("nop");
+LL | |     }
+   | |_____^
+   |
+note: union field access occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:58:14
+   |
+LL |         drop(u.u);
+   |              ^^^
+note: access of a mutable static occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:59:14
+   |
+LL |         drop(STATIC);
+   |              ^^^^^^
+note: unsafe method call occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:60:9
+   |
+LL |         sample.not_very_safe();
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+note: unsafe function call occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:61:9
+   |
+LL |         not_very_safe();
+   |         ^^^^^^^^^^^^^^^
+note: raw pointer dereference occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:62:9
+   |
+LL |         *raw_ptr();
+   |         ^^^^^^^^^^
+note: inline assembly used here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:63:9
+   |
+LL |         asm!("nop");
+   |         ^^^^^^^^^^^
+
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+  --> $DIR/multiple_unsafe_ops_per_block.rs:101:5
+   |
+LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: unsafe function call occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:101:14
+   |
+LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: raw pointer dereference occurs here
+  --> $DIR/multiple_unsafe_ops_per_block.rs:101:39
+   |
+LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+   |                                       ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
index ab1c0e590bbc7ca317ea0568eebee557090b7623..079e3531def1b04d83f6adcfba39c9dd8e270eb5 100644 (file)
@@ -31,6 +31,16 @@ fn test_no_semicolon() -> bool {
     true
 }
 
+#[rustfmt::skip]
+fn test_multiple_semicolon() -> bool {
+    true
+}
+
+#[rustfmt::skip]
+fn test_multiple_semicolon_with_spaces() -> bool {
+    true
+}
+
 fn test_if_block() -> bool {
     if true {
         true
index abed338bb9b297c415a2cf0115728cd54e6f29a5..c1c48284f086901d31e9353426684e967f52f76f 100644 (file)
@@ -31,6 +31,16 @@ fn test_no_semicolon() -> bool {
     return true;
 }
 
+#[rustfmt::skip]
+fn test_multiple_semicolon() -> bool {
+    return true;;;
+}
+
+#[rustfmt::skip]
+fn test_multiple_semicolon_with_spaces() -> bool {
+    return true;; ; ;
+}
+
 fn test_if_block() -> bool {
     if true {
         return true;
index 52eabf6e1370dd2235f22cfbb958464e03d3e746..08b04bfe9d8bfb120d0ee48329fa3b9114852628 100644 (file)
@@ -16,7 +16,23 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:36:9
+  --> $DIR/needless_return.rs:36:5
+   |
+LL |     return true;;;
+   |     ^^^^^^^^^^^
+   |
+   = help: remove `return`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:41:5
+   |
+LL |     return true;; ; ;
+   |     ^^^^^^^^^^^
+   |
+   = help: remove `return`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:46:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -24,7 +40,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:38:9
+  --> $DIR/needless_return.rs:48:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -32,7 +48,7 @@ LL |         return false;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:44:17
+  --> $DIR/needless_return.rs:54:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^
@@ -40,7 +56,7 @@ LL |         true => return false,
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:46:13
+  --> $DIR/needless_return.rs:56:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^
@@ -48,7 +64,7 @@ LL |             return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:53:9
+  --> $DIR/needless_return.rs:63:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -56,7 +72,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:55:16
+  --> $DIR/needless_return.rs:65:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^
@@ -64,7 +80,7 @@ LL |     let _ = || return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:59:5
+  --> $DIR/needless_return.rs:69:5
    |
 LL |     return the_answer!();
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +88,7 @@ LL |     return the_answer!();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:62:21
+  --> $DIR/needless_return.rs:72:21
    |
 LL |   fn test_void_fun() {
    |  _____________________^
@@ -82,7 +98,7 @@ LL | |     return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:67:11
+  --> $DIR/needless_return.rs:77:11
    |
 LL |       if b {
    |  ___________^
@@ -92,7 +108,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:69:13
+  --> $DIR/needless_return.rs:79:13
    |
 LL |       } else {
    |  _____________^
@@ -102,7 +118,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:77:14
+  --> $DIR/needless_return.rs:87:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -110,7 +126,7 @@ LL |         _ => return,
    = help: replace `return` with a unit value
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:85:24
+  --> $DIR/needless_return.rs:95:24
    |
 LL |               let _ = 42;
    |  ________________________^
@@ -120,7 +136,7 @@ LL | |             return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:88:14
+  --> $DIR/needless_return.rs:98:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -128,7 +144,7 @@ LL |         _ => return,
    = help: replace `return` with a unit value
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:101:9
+  --> $DIR/needless_return.rs:111:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -136,7 +152,7 @@ LL |         return String::from("test");
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:103:9
+  --> $DIR/needless_return.rs:113:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -144,7 +160,7 @@ LL |         return String::new();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:125:32
+  --> $DIR/needless_return.rs:135:32
    |
 LL |         bar.unwrap_or_else(|_| return)
    |                                ^^^^^^
@@ -152,7 +168,7 @@ LL |         bar.unwrap_or_else(|_| return)
    = help: replace `return` with an empty block
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:129:21
+  --> $DIR/needless_return.rs:139:21
    |
 LL |           let _ = || {
    |  _____________________^
@@ -162,7 +178,7 @@ LL | |             return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:132:20
+  --> $DIR/needless_return.rs:142:20
    |
 LL |         let _ = || return;
    |                    ^^^^^^
@@ -170,7 +186,7 @@ LL |         let _ = || return;
    = help: replace `return` with an empty block
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:138:32
+  --> $DIR/needless_return.rs:148:32
    |
 LL |         res.unwrap_or_else(|_| return Foo)
    |                                ^^^^^^^^^^
@@ -178,7 +194,7 @@ LL |         res.unwrap_or_else(|_| return Foo)
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:147:5
+  --> $DIR/needless_return.rs:157:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -186,7 +202,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:151:5
+  --> $DIR/needless_return.rs:161:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -194,7 +210,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:156:9
+  --> $DIR/needless_return.rs:166:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -202,7 +218,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:158:9
+  --> $DIR/needless_return.rs:168:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -210,7 +226,7 @@ LL |         return false;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:164:17
+  --> $DIR/needless_return.rs:174:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^
@@ -218,7 +234,7 @@ LL |         true => return false,
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:166:13
+  --> $DIR/needless_return.rs:176:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^
@@ -226,7 +242,7 @@ LL |             return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:173:9
+  --> $DIR/needless_return.rs:183:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -234,7 +250,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:175:16
+  --> $DIR/needless_return.rs:185:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^
@@ -242,7 +258,7 @@ LL |     let _ = || return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:179:5
+  --> $DIR/needless_return.rs:189:5
    |
 LL |     return the_answer!();
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -250,7 +266,7 @@ LL |     return the_answer!();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:182:33
+  --> $DIR/needless_return.rs:192:33
    |
 LL |   async fn async_test_void_fun() {
    |  _________________________________^
@@ -260,7 +276,7 @@ LL | |     return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:187:11
+  --> $DIR/needless_return.rs:197:11
    |
 LL |       if b {
    |  ___________^
@@ -270,7 +286,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:189:13
+  --> $DIR/needless_return.rs:199:13
    |
 LL |       } else {
    |  _____________^
@@ -280,7 +296,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:197:14
+  --> $DIR/needless_return.rs:207:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -288,7 +304,7 @@ LL |         _ => return,
    = help: replace `return` with a unit value
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:210:9
+  --> $DIR/needless_return.rs:220:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -296,7 +312,7 @@ LL |         return String::from("test");
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:212:9
+  --> $DIR/needless_return.rs:222:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -304,7 +320,7 @@ LL |         return String::new();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:228:5
+  --> $DIR/needless_return.rs:238:5
    |
 LL |     return format!("Hello {}", "world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -312,7 +328,7 @@ LL |     return format!("Hello {}", "world!");
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:239:9
+  --> $DIR/needless_return.rs:249:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -320,7 +336,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:241:9
+  --> $DIR/needless_return.rs:251:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -328,7 +344,7 @@ LL |         return false;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:248:13
+  --> $DIR/needless_return.rs:258:13
    |
 LL |             return 10;
    |             ^^^^^^^^^
@@ -336,7 +352,7 @@ LL |             return 10;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:251:13
+  --> $DIR/needless_return.rs:261:13
    |
 LL |             return 100;
    |             ^^^^^^^^^^
@@ -344,7 +360,7 @@ LL |             return 100;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:259:9
+  --> $DIR/needless_return.rs:269:9
    |
 LL |         return 0;
    |         ^^^^^^^^
@@ -352,7 +368,7 @@ LL |         return 0;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:266:13
+  --> $DIR/needless_return.rs:276:13
    |
 LL |             return *(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -360,7 +376,7 @@ LL |             return *(x as *const isize);
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:268:13
+  --> $DIR/needless_return.rs:278:13
    |
 LL |             return !*(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -368,7 +384,7 @@ LL |             return !*(x as *const isize);
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:275:20
+  --> $DIR/needless_return.rs:285:20
    |
 LL |           let _ = 42;
    |  ____________________^
@@ -379,7 +395,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:282:20
+  --> $DIR/needless_return.rs:292:20
    |
 LL |         let _ = 42; return;
    |                    ^^^^^^^
@@ -387,7 +403,7 @@ LL |         let _ = 42; return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:294:9
+  --> $DIR/needless_return.rs:304:9
    |
 LL |         return Ok(format!("ok!"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -395,12 +411,12 @@ LL |         return Ok(format!("ok!"));
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:296:9
+  --> $DIR/needless_return.rs:306:9
    |
 LL |         return Err(format!("err!"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: remove `return`
 
-error: aborting due to 48 previous errors
+error: aborting due to 50 previous errors
 
index 7263abac15dfb96978597c5af32f24a4fb12ad25..55307506eb3c74ca246381a58aaddf42eade4616 100644 (file)
@@ -51,6 +51,8 @@ fn main() {
     // e is a function pointer type and U is an integer; fptr-addr-cast
     let _usize_from_fn_ptr_transmute = unsafe { foo as usize };
     let _usize_from_fn_ptr = foo as *const usize;
+
+    let _usize_from_ref = unsafe { &1u32 as *const u32 as usize };
 }
 
 // If a ref-to-ptr cast of this form where the pointer type points to a type other
index d8e4421d4c18e2a3743100bc15e037d3b8525e24..e7360f3f9dcbaacc48e1607b95e6bfaa8982f939 100644 (file)
@@ -51,6 +51,8 @@ fn foo(_: usize) -> u8 {
     // e is a function pointer type and U is an integer; fptr-addr-cast
     let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };
     let _usize_from_fn_ptr = foo as *const usize;
+
+    let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) };
 }
 
 // If a ref-to-ptr cast of this form where the pointer type points to a type other
index de9418c8d1adc4af6ab0e578ef3697b2a95a1c72..e862fcb67a4a086421355728a997c318126e2594 100644 (file)
@@ -46,11 +46,17 @@ error: transmute from `fn(usize) -> u8` to `usize` which could be expressed as a
 LL |     let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize`
 
+error: transmute from `*const u32` to `usize` which could be expressed as a pointer cast instead
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:55:36
+   |
+LL |     let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) };
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&1u32 as *const u32 as usize`
+
 error: transmute from a reference to a pointer
-  --> $DIR/transmutes_expressible_as_ptr_casts.rs:64:14
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:66:14
    |
 LL |     unsafe { transmute::<&[i32; 1], *const u8>(in_param) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8`
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
index 7fefea7051d698ce92aab8e5c9dc6b48242e2564..89fedb145f88bd2c75748559237c58477e0fe6a3 100644 (file)
@@ -48,4 +48,21 @@ fn unnecessary_on_stmt_and_expr() -> u32 {
     24
 }
 
+mod issue_10084 {
+    unsafe fn bar() -> i32 {
+        42
+    }
+
+    macro_rules! foo {
+        () => {
+            // SAFETY: This is necessary
+            unsafe { bar() }
+        };
+    }
+
+    fn main() {
+        foo!();
+    }
+}
+
 fn main() {}
index a5f5eb447da6ccdde644a47e48c4ef2705986ec4..3676f69b100db0136b8701413a1e15513a634399 100644 (file)
@@ -123,6 +123,7 @@ pub enum FailMode {
 pub enum CompareMode {
     Polonius,
     Chalk,
+    NextSolver,
     SplitDwarf,
     SplitDwarfSingle,
 }
@@ -132,6 +133,7 @@ pub(crate) fn to_str(&self) -> &'static str {
         match *self {
             CompareMode::Polonius => "polonius",
             CompareMode::Chalk => "chalk",
+            CompareMode::NextSolver => "next-solver",
             CompareMode::SplitDwarf => "split-dwarf",
             CompareMode::SplitDwarfSingle => "split-dwarf-single",
         }
@@ -141,6 +143,7 @@ pub fn parse(s: String) -> CompareMode {
         match s.as_str() {
             "polonius" => CompareMode::Polonius,
             "chalk" => CompareMode::Chalk,
+            "next-solver" => CompareMode::NextSolver,
             "split-dwarf" => CompareMode::SplitDwarf,
             "split-dwarf-single" => CompareMode::SplitDwarfSingle,
             x => panic!("unknown --compare-mode option: {}", x),
index c5767a795382e41a7af9413e8e30adc609b2c3ee..45fd87bea9bb5ac72437553c8c2de59c01741239 100644 (file)
@@ -162,6 +162,9 @@ pub struct TestProps {
     pub stderr_per_bitwidth: bool,
     // The MIR opt to unit test, if any
     pub mir_unit_test: Option<String>,
+    // Whether to tell `rustc` to remap the "src base" directory to a fake
+    // directory.
+    pub remap_src_base: bool,
 }
 
 mod directives {
@@ -196,6 +199,7 @@ mod directives {
     pub const INCREMENTAL: &'static str = "incremental";
     pub const KNOWN_BUG: &'static str = "known-bug";
     pub const MIR_UNIT_TEST: &'static str = "unit-test";
+    pub const REMAP_SRC_BASE: &'static str = "remap-src-base";
     // This isn't a real directive, just one that is probably mistyped often
     pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags";
 }
@@ -241,6 +245,7 @@ pub fn new() -> Self {
             should_ice: false,
             stderr_per_bitwidth: false,
             mir_unit_test: None,
+            remap_src_base: false,
         }
     }
 
@@ -273,6 +278,9 @@ pub fn from_file(testfile: &Path, cfg: Option<&str>, config: &Config) -> Self {
     /// `//[foo]`), then the property is ignored unless `cfg` is
     /// `Some("foo")`.
     fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
+        // Mode-dependent defaults.
+        self.remap_src_base = config.mode == Mode::Ui && !config.suite.contains("rustdoc");
+
         let mut has_edition = false;
         if !testfile.is_dir() {
             let file = File::open(testfile).unwrap();
@@ -426,13 +434,19 @@ fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
                         self.known_bug = true;
                     } else {
                         panic!(
-                            "Invalid known-bug value: {known_bug}\nIt requires comma-separated issue references (`#000` or `chalk#000`) or `unknown`."
+                            "Invalid known-bug value: {known_bug}\nIt requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`."
                         );
                     }
+                } else if config.parse_name_directive(ln, KNOWN_BUG) {
+                    panic!(
+                        "Invalid known-bug attribute, requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`."
+                    );
                 }
+
                 config.set_name_value_directive(ln, MIR_UNIT_TEST, &mut self.mir_unit_test, |s| {
                     s.trim().to_string()
                 });
+                config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base);
             });
         }
 
@@ -696,6 +710,7 @@ fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirect
             match self.compare_mode {
                 Some(CompareMode::Polonius) => name == "compare-mode-polonius",
                 Some(CompareMode::Chalk) => name == "compare-mode-chalk",
+                Some(CompareMode::NextSolver) => name == "compare-mode-next-solver",
                 Some(CompareMode::SplitDwarf) => name == "compare-mode-split-dwarf",
                 Some(CompareMode::SplitDwarfSingle) => name == "compare-mode-split-dwarf-single",
                 None => false,
@@ -725,6 +740,10 @@ fn parse_name_directive(&self, line: &str, directive: &str) -> bool {
             && matches!(line.as_bytes().get(directive.len()), None | Some(&b' ') | Some(&b':'))
     }
 
+    fn parse_negative_name_directive(&self, line: &str, directive: &str) -> bool {
+        line.starts_with("no-") && self.parse_name_directive(&line[3..], directive)
+    }
+
     pub fn parse_name_value_directive(&self, line: &str, directive: &str) -> Option<String> {
         let colon = directive.len();
         if line.starts_with(directive) && line.as_bytes().get(colon) == Some(&b':') {
@@ -754,8 +773,17 @@ fn parse_edition(&self, line: &str) -> Option<String> {
     }
 
     fn set_name_directive(&self, line: &str, directive: &str, value: &mut bool) {
-        if !*value {
-            *value = self.parse_name_directive(line, directive)
+        match value {
+            true => {
+                if self.parse_negative_name_directive(line, directive) {
+                    *value = false;
+                }
+            }
+            false => {
+                if self.parse_name_directive(line, directive) {
+                    *value = true;
+                }
+            }
         }
     }
 
@@ -898,7 +926,7 @@ pub fn make_test_description<R: Read>(
     cfg: Option<&str>,
 ) -> test::TestDesc {
     let mut ignore = false;
-    let ignore_message = None;
+    let mut ignore_message = None;
     let mut should_fail = false;
 
     let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
@@ -938,41 +966,67 @@ pub fn make_test_description<R: Read>(
         if revision.is_some() && revision != cfg {
             return;
         }
+        macro_rules! reason {
+            ($e:expr) => {
+                ignore |= match $e {
+                    true => {
+                        ignore_message = Some(stringify!($e));
+                        true
+                    }
+                    false => ignore,
+                }
+            };
+        }
         ignore = match config.parse_cfg_name_directive(ln, "ignore") {
-            ParsedNameDirective::Match => true,
+            ParsedNameDirective::Match => {
+                ignore_message = Some("cfg -> ignore => Match");
+                true
+            }
             ParsedNameDirective::NoMatch => ignore,
         };
+
         if config.has_cfg_prefix(ln, "only") {
             ignore = match config.parse_cfg_name_directive(ln, "only") {
                 ParsedNameDirective::Match => ignore,
-                ParsedNameDirective::NoMatch => true,
+                ParsedNameDirective::NoMatch => {
+                    ignore_message = Some("cfg -> only => NoMatch");
+                    true
+                }
             };
         }
-        ignore |= ignore_llvm(config, ln);
-        ignore |=
-            config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln);
-        ignore |= !has_asm_support && config.parse_name_directive(ln, "needs-asm-support");
-        ignore |= !rustc_has_profiler_support && config.parse_needs_profiler_support(ln);
-        ignore |= !config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled");
-        ignore |= !rustc_has_sanitizer_support
-            && config.parse_name_directive(ln, "needs-sanitizer-support");
-        ignore |= !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address");
-        ignore |= !has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi");
-        ignore |= !has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi");
-        ignore |= !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak");
-        ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory");
-        ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread");
-        ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress");
-        ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag");
-        ignore |= !has_shadow_call_stack
-            && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack");
-        ignore |= !config.can_unwind() && config.parse_name_directive(ln, "needs-unwind");
-        ignore |= config.target == "wasm32-unknown-unknown"
-            && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS);
-        ignore |= config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln);
-        ignore |= config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln);
-        ignore |= config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln);
-        ignore |= !has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld");
+
+        reason!(ignore_llvm(config, ln));
+        reason!(
+            config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln)
+        );
+        reason!(!has_asm_support && config.parse_name_directive(ln, "needs-asm-support"));
+        reason!(!rustc_has_profiler_support && config.parse_needs_profiler_support(ln));
+        reason!(!config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled"));
+        reason!(
+            !rustc_has_sanitizer_support
+                && config.parse_name_directive(ln, "needs-sanitizer-support")
+        );
+        reason!(!has_asan && config.parse_name_directive(ln, "needs-sanitizer-address"));
+        reason!(!has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi"));
+        reason!(!has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi"));
+        reason!(!has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak"));
+        reason!(!has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory"));
+        reason!(!has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread"));
+        reason!(!has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress"));
+        reason!(!has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag"));
+        reason!(
+            !has_shadow_call_stack
+                && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack")
+        );
+        reason!(!config.can_unwind() && config.parse_name_directive(ln, "needs-unwind"));
+        reason!(
+            config.target == "wasm32-unknown-unknown"
+                && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS)
+        );
+        reason!(config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln));
+        reason!(config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln));
+        reason!(config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln));
+        reason!(!has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld"));
         should_fail |= config.parse_name_directive(ln, "should-fail");
     });
 
index 2aea30870ff5e6dc97ebf1543ebe6b5cb34fd34b..3092c656cd729ba787276b95d199b2afbe15fb8f 100644 (file)
@@ -775,7 +775,7 @@ fn make_test_name(
 ) -> test::TestName {
     // Print the name of the file, relative to the repository root.
     // `src_base` looks like `/path/to/rust/tests/ui`
-    let root_directory = config.src_base.parent().unwrap().parent().unwrap().parent().unwrap();
+    let root_directory = config.src_base.parent().unwrap().parent().unwrap();
     let path = testpaths.file.strip_prefix(root_directory).unwrap();
     let debugger = match config.debugger {
         Some(d) => format!("-{}", d),
index 7640e6517442881ca3089c9745b324e9860b1e29..a5dc6859732a3d2c5348fb8084e00e0afbd876a5 100644 (file)
@@ -110,9 +110,18 @@ fn extend(&mut self, data: &[u8], filter_paths_from_len: &[String]) {
     fn into_bytes(self) -> Vec<u8> {
         match self {
             ProcOutput::Full { bytes, .. } => bytes,
-            ProcOutput::Abbreviated { mut head, skipped, tail } => {
+            ProcOutput::Abbreviated { mut head, mut skipped, tail } => {
+                let mut tail = &*tail;
+
+                // Skip over '{' at the start of the tail, so we don't later wrongfully consider this as json.
+                // See <https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Weird.20CI.20failure/near/321797811>
+                while tail.get(0) == Some(&b'{') {
+                    tail = &tail[1..];
+                    skipped += 1;
+                }
+
                 write!(&mut head, "\n\n<<<<<< SKIPPED {} BYTES >>>>>>\n\n", skipped).unwrap();
-                head.extend_from_slice(&tail);
+                head.extend_from_slice(tail);
                 head
             }
         }
index a16ab11e2f9788b377edbae1511983c05b9d3b60..51c9a27c83d51cfbb0e7dac0541d66e5ea4b1977 100644 (file)
@@ -44,6 +44,8 @@
 #[cfg(test)]
 mod tests;
 
+const FAKE_SRC_BASE: &str = "fake-test-src-base";
+
 #[cfg(windows)]
 fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
     use std::sync::Mutex;
@@ -1328,12 +1330,19 @@ fn check_expected_errors(&self, expected_errors: Vec<errors::Error>, proc_res: &
             return;
         }
 
+        // On Windows, translate all '\' path separators to '/'
+        let file_name = format!("{}", self.testpaths.file.display()).replace(r"\", "/");
+
         // On Windows, keep all '\' path separators to match the paths reported in the JSON output
         // from the compiler
-        let os_file_name = self.testpaths.file.display().to_string();
-
-        // on windows, translate all '\' path separators to '/'
-        let file_name = format!("{}", self.testpaths.file.display()).replace(r"\", "/");
+        let diagnostic_file_name = if self.props.remap_src_base {
+            let mut p = PathBuf::from(FAKE_SRC_BASE);
+            p.push(&self.testpaths.relative_dir);
+            p.push(self.testpaths.file.file_name().unwrap());
+            p.display().to_string()
+        } else {
+            self.testpaths.file.display().to_string()
+        };
 
         // If the testcase being checked contains at least one expected "help"
         // message, then we'll ensure that all "help" messages are expected.
@@ -1343,7 +1352,7 @@ fn check_expected_errors(&self, expected_errors: Vec<errors::Error>, proc_res: &
         let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note));
 
         // Parse the JSON output from the compiler and extract out the messages.
-        let actual_errors = json::parse_output(&os_file_name, &proc_res.stderr, proc_res);
+        let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res);
         let mut unexpected = Vec::new();
         let mut found = vec![false; expected_errors.len()];
         for actual_error in &actual_errors {
@@ -1970,6 +1979,14 @@ fn make_compile_args(
             }
         }
 
+        if self.props.remap_src_base {
+            rustc.arg(format!(
+                "--remap-path-prefix={}={}",
+                self.config.src_base.display(),
+                FAKE_SRC_BASE,
+            ));
+        }
+
         match emit {
             Emit::None => {}
             Emit::Metadata if is_rustdoc => {}
@@ -2013,6 +2030,9 @@ fn make_compile_args(
             Some(CompareMode::Chalk) => {
                 rustc.args(&["-Ztrait-solver=chalk"]);
             }
+            Some(CompareMode::NextSolver) => {
+                rustc.args(&["-Ztrait-solver=next"]);
+            }
             Some(CompareMode::SplitDwarf) if self.config.target.contains("windows") => {
                 rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]);
             }
@@ -3545,6 +3565,14 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
         let parent_dir = self.testpaths.file.parent().unwrap();
         normalize_path(parent_dir, "$DIR");
 
+        if self.props.remap_src_base {
+            let mut remapped_parent_dir = PathBuf::from(FAKE_SRC_BASE);
+            if self.testpaths.relative_dir != Path::new("") {
+                remapped_parent_dir.push(&self.testpaths.relative_dir);
+            }
+            normalize_path(&remapped_parent_dir, "$DIR");
+        }
+
         let source_bases = &[
             // Source base on the current filesystem (calculated as parent of `tests/$suite`):
             Some(self.config.src_base.parent().unwrap().parent().unwrap().into()),
index 6c63b760ff6a9de167c26c783851beee3dbc2981..ff7e8df987816ec29614a59a9450ba3bf8dd3ad7 100644 (file)
@@ -23,6 +23,7 @@
     "x86_64-linux-android",
     "x86_64-unknown-freebsd",
     "x86_64-unknown-linux-gnu",
+    "s390x-unknown-linux-gnu",
 ];
 
 // FIXME(rcvalle): More targets are likely supported.
     "aarch64-unknown-linux-gnu",
     "x86_64-apple-darwin",
     "x86_64-unknown-linux-gnu",
+    "s390x-unknown-linux-gnu",
 ];
 
-pub const MSAN_SUPPORTED_TARGETS: &[&str] =
-    &["aarch64-unknown-linux-gnu", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu"];
+pub const MSAN_SUPPORTED_TARGETS: &[&str] = &[
+    "aarch64-unknown-linux-gnu",
+    "x86_64-unknown-freebsd",
+    "x86_64-unknown-linux-gnu",
+    "s390x-unknown-linux-gnu",
+];
 
 pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[
     "aarch64-apple-darwin",
@@ -61,6 +67,7 @@
     "x86_64-apple-darwin",
     "x86_64-unknown-freebsd",
     "x86_64-unknown-linux-gnu",
+    "s390x-unknown-linux-gnu",
 ];
 
 pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
index 6a147de3be2eac3acd613f75eecc4d41c90e49c9..c0267956aab4ab714da49b422f5a8fb1eaa4e972 100644 (file)
@@ -56,12 +56,12 @@ fn config(&mut self, config: &mut Config) {
 
     fn after_analysis<'tcx>(
         &mut self,
-        compiler: &rustc_interface::interface::Compiler,
+        _: &rustc_interface::interface::Compiler,
         queries: &'tcx rustc_interface::Queries<'tcx>,
     ) -> Compilation {
-        compiler.session().abort_if_errors();
-
         queries.global_ctxt().unwrap().enter(|tcx| {
+            tcx.sess.abort_if_errors();
+
             init_late_loggers(tcx);
             if !tcx.sess.crate_types().contains(&CrateType::Executable) {
                 tcx.sess.fatal("miri only makes sense on bin crates");
@@ -75,7 +75,7 @@ fn after_analysis<'tcx>(
             let mut config = self.miri_config.clone();
 
             // Add filename to `miri` arguments.
-            config.args.insert(0, compiler.input().filestem().to_string());
+            config.args.insert(0, tcx.sess.io.input.filestem().to_string());
 
             // Adjust working directory for interpretation.
             if let Some(cwd) = env::var_os("MIRI_CWD") {
@@ -87,10 +87,9 @@ fn after_analysis<'tcx>(
                     i32::try_from(return_code).expect("Return value was too large!"),
                 );
             }
+            tcx.sess.abort_if_errors();
         });
 
-        compiler.session().abort_if_errors();
-
         Compilation::Stop
     }
 }
index 6c87dad1f1f4ab0a83e30a078854c13592a3c0dd..96ab8b0d98e6348c794782bc00eb99be510d74bf 100644 (file)
@@ -357,7 +357,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
     match entry_type {
         EntryFnType::Main { .. } => {
             let start_id = tcx.lang_items().start_fn().unwrap();
-            let main_ret_ty = tcx.fn_sig(entry_id).output();
+            let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output();
             let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
             let start_instance = ty::Instance::resolve(
                 tcx,
index f1838cf64f7feefbf5d5b0a01f7e8c5e3fe7fd9a..d6d19a3fe8159ccc66ceb1ad7cf44e9ba9da742b 100644 (file)
@@ -22,7 +22,8 @@ fn main() {
     }
 
     // test `stat`
-    assert_eq!(fs::metadata("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied);
+    let err = fs::metadata("foo.txt").unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::PermissionDenied);
     // check that it is the right kind of `PermissionDenied`
-    assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES));
+    assert_eq!(err.raw_os_error(), Some(libc::EACCES));
 }
index 3a6655e2ba69f5bfa5daa1394721b3011cfac622..30a28bc5803ddf41f0479606e9e94ca99d06d6c3 100644 (file)
@@ -162,6 +162,11 @@ fn reverse() {
     assert!(v[0].0 == 49);
 }
 
+fn miri_issue_2759() {
+    let mut input = "1".to_string();
+    input.replace_range(0..0, "0");
+}
+
 fn main() {
     assert_eq!(vec_reallocate().len(), 5);
 
@@ -191,4 +196,5 @@ fn main() {
     swap();
     swap_remove();
     reverse();
+    miri_issue_2759();
 }
index 9c16ef2cbeccca1e91a4491f95341d7203dc1724..395bcc745f8dd75edf9654a324f26268e2479444 100755 (executable)
@@ -68,52 +68,6 @@ def load_json_from_response(resp):
         print("Refusing to decode " + str(type(content)) + " to str")
     return json.loads(content_str)
 
-def validate_maintainers(repo, github_token):
-    # type: (str, str) -> None
-    '''Ensure all maintainers are assignable on a GitHub repo'''
-    next_link_re = re.compile(r'<([^>]+)>; rel="next"')
-
-    # Load the list of assignable people in the GitHub repo
-    assignable = [] # type: typing.List[str]
-    url = 'https://api.github.com/repos/' \
-        + '%s/collaborators?per_page=100' % repo # type: typing.Optional[str]
-    while url is not None:
-        response = urllib2.urlopen(urllib2.Request(url, headers={
-            'Authorization': 'token ' + github_token,
-            # Properly load nested teams.
-            'Accept': 'application/vnd.github.hellcat-preview+json',
-        }))
-        assignable.extend(user['login'] for user in load_json_from_response(response))
-        # Load the next page if available
-        url = None
-        link_header = response.headers.get('Link')
-        if link_header:
-            matches = next_link_re.match(link_header)
-            if matches is not None:
-                url = matches.group(1)
-
-    errors = False
-    for tool, maintainers in MAINTAINERS.items():
-        for maintainer in maintainers:
-            if maintainer not in assignable:
-                errors = True
-                print(
-                    "error: %s maintainer @%s is not assignable in the %s repo"
-                    % (tool, maintainer, repo),
-                )
-
-    if errors:
-        print()
-        print("  To be assignable, a person needs to be explicitly listed as a")
-        print("  collaborator in the repository settings. The simple way to")
-        print("  fix this is to ask someone with 'admin' privileges on the repo")
-        print("  to add the person or whole team as a collaborator with 'read'")
-        print("  privileges. Those privileges don't grant any extra permissions")
-        print("  so it's safe to apply them.")
-        print()
-        print("The build will fail due to this.")
-        exit(1)
-
 
 def read_current_status(current_commit, path):
     # type: (str, str) -> typing.Mapping[str, typing.Any]
@@ -280,21 +234,6 @@ def update_latest(
 try:
     if __name__ != '__main__':
         exit(0)
-    repo = os.environ.get('TOOLSTATE_VALIDATE_MAINTAINERS_REPO')
-    if repo:
-        github_token = os.environ.get('TOOLSTATE_REPO_ACCESS_TOKEN')
-        if github_token:
-            # FIXME: This is currently broken. Starting on 2021-09-15, GitHub
-            # seems to have changed it so that to list the collaborators
-            # requires admin permissions. I think this will probably just need
-            # to be removed since we are probably not going to use an admin
-            # token, and I don't see another way to do this.
-            print('maintainer validation disabled')
-            # validate_maintainers(repo, github_token)
-        else:
-            print('skipping toolstate maintainers validation since no GitHub token is present')
-        # When validating maintainers don't run the full script.
-        exit(0)
 
     cur_commit = sys.argv[1]
     cur_datetime = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
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 fff83a1d097b3f6364c180781b8bfdb6ec886dc6..cdf1dd366046c56c92d285239cef4ecc9101e251 100644 (file)
@@ -6,11 +6,13 @@ autobins = false
 
 [dependencies]
 cargo_metadata = "0.14"
+cargo-platform = "0.1.2"
 regex = "1"
 miropt-test-tools = { path = "../miropt-test-tools" }
 lazy_static = "1"
 walkdir = "2"
 ignore = "0.4.18"
+semver = "1.0"
 termcolor = "1.1.3"
 
 [[bin]]
index 845eb5af0d6bb33271b0896b340742eb5c950ff3..8ce19c8b5145b818342fa6b5e797ab825bb5bba8 100644 (file)
@@ -1,7 +1,7 @@
 //! Checks the licenses of third-party dependencies.
 
-use cargo_metadata::{Metadata, Package, PackageId, Resolve};
-use std::collections::{BTreeSet, HashSet};
+use cargo_metadata::{DepKindInfo, Metadata, Package, PackageId};
+use std::collections::HashSet;
 use std::path::Path;
 
 /// These are licenses that are allowed for all crates, including the runtime,
@@ -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"),
     "autocfg",
     "bitflags",
     "block-buffer",
-    "bumpalo", // Included in Cargo's dep graph but only activated on wasm32-*-unknown.
     "cc",
     "cfg-if",
     "chalk-derive",
     "chalk-engine",
     "chalk-ir",
     "chalk-solve",
-    "chrono",
     "convert_case", // dependency of derive_more
     "compiler_builtins",
     "cpufeatures",
     "dlmalloc",
     "either",
     "ena",
-    "env_logger",
     "expect-test",
     "fallible-iterator", // dependency of `thorin`
     "fastrand",
-    "filetime",
     "fixedbitset",
     "flate2",
     "fluent-bundle",
     "gsgdt",
     "hashbrown",
     "hermit-abi",
-    "humantime",
     "icu_list",
     "icu_locid",
     "icu_provider",
     "icu_provider_adapters",
     "icu_provider_macros",
-    "if_chain",
     "indexmap",
     "instant",
     "intl-memoizer",
     "itertools",
     "itoa",
     "jobserver",
-    "js-sys", // Included in Cargo's dep graph but only activated on wasm32-*-unknown.
     "lazy_static",
     "libc",
     "libloading",
     "memmap2",
     "memoffset",
     "miniz_oxide",
-    "num-integer",
-    "num-traits",
     "num_cpus",
     "object",
     "odht",
     "proc-macro2",
     "psm",
     "punycode",
-    "quick-error",
     "quote",
     "rand",
     "rand_chacha",
     "thiserror-impl",
     "thorin-dwp",
     "thread_local",
-    "time",
     "tinystr",
     "tinyvec",
     "tinyvec_macros",
     "valuable",
     "version_check",
     "wasi",
-    // vvv Included in Cargo's dep graph but only activated on wasm32-*-unknown.
-    "wasm-bindgen",
-    "wasm-bindgen-backend",
-    "wasm-bindgen-macro",
-    "wasm-bindgen-macro-support",
-    "wasm-bindgen-shared",
-    // ^^^ Included in Cargo's dep graph but only activated on wasm32-*-unknown.
     "winapi",
     "winapi-i686-pc-windows-gnu",
     "winapi-util",
     "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",
 ];
 
@@ -485,73 +467,55 @@ fn check_permitted_dependencies(
     restricted_dependency_crates: &[&'static str],
     bad: &mut bool,
 ) {
+    let mut deps = HashSet::new();
+    for to_check in restricted_dependency_crates {
+        let to_check = pkg_from_name(metadata, to_check);
+        use cargo_platform::Cfg;
+        use std::str::FromStr;
+        // We don't expect the compiler to ever run on wasm32, so strip
+        // out those dependencies to avoid polluting the permitted list.
+        deps_of_filtered(metadata, &to_check.id, &mut deps, &|dep_kinds| {
+            dep_kinds.iter().any(|dep_kind| {
+                dep_kind
+                    .target
+                    .as_ref()
+                    .map(|target| {
+                        !target.matches(
+                            "wasm32-unknown-unknown",
+                            &[
+                                Cfg::from_str("target_arch=\"wasm32\"").unwrap(),
+                                Cfg::from_str("target_os=\"unknown\"").unwrap(),
+                            ],
+                        )
+                    })
+                    .unwrap_or(true)
+            })
+        });
+    }
+
     // Check that the PERMITTED_DEPENDENCIES does not have unused entries.
-    for name in permitted_dependencies {
-        if !metadata.packages.iter().any(|p| p.name == *name) {
+    for permitted in permitted_dependencies {
+        if !deps.iter().any(|dep_id| &pkg_from_id(metadata, dep_id).name == permitted) {
             tidy_error!(
                 bad,
-                "could not find allowed package `{}`\n\
+                "could not find allowed package `{permitted}`\n\
                 Remove from PERMITTED_DEPENDENCIES list if it is no longer used.",
-                name
             );
         }
     }
-    // Get the list in a convenient form.
-    let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect();
-
-    // Check dependencies.
-    let mut visited = BTreeSet::new();
-    let mut unapproved = BTreeSet::new();
-    for &krate in restricted_dependency_crates.iter() {
-        let pkg = pkg_from_name(metadata, krate);
-        let mut bad =
-            check_crate_dependencies(&permitted_dependencies, metadata, &mut visited, pkg);
-        unapproved.append(&mut bad);
-    }
-
-    if !unapproved.is_empty() {
-        tidy_error!(bad, "Dependencies for {} not explicitly permitted:", descr);
-        for dep in unapproved {
-            println!("* {dep}");
-        }
-    }
-}
-
-/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
-/// the list of permitted dependencies. Returns a list of disallowed dependencies.
-fn check_crate_dependencies<'a>(
-    permitted_dependencies: &'a HashSet<&'static str>,
-    metadata: &'a Metadata,
-    visited: &mut BTreeSet<&'a PackageId>,
-    krate: &'a Package,
-) -> BTreeSet<&'a PackageId> {
-    // This will contain bad deps.
-    let mut unapproved = BTreeSet::new();
-
-    // Check if we have already visited this crate.
-    if visited.contains(&krate.id) {
-        return unapproved;
-    }
 
-    visited.insert(&krate.id);
+    // Get in a convenient form.
+    let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect();
 
-    // If this path is in-tree, we don't require it to be explicitly permitted.
-    if krate.source.is_some() {
-        // If this dependency is not on `PERMITTED_DEPENDENCIES`, add to bad set.
-        if !permitted_dependencies.contains(krate.name.as_str()) {
-            unapproved.insert(&krate.id);
+    for dep in deps {
+        let dep = pkg_from_id(metadata, dep);
+        // If this path is in-tree, we don't require it to be explicitly permitted.
+        if dep.source.is_some() {
+            if !permitted_dependencies.contains(dep.name.as_str()) {
+                tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id);
+            }
         }
     }
-
-    // Do a DFS in the crate graph.
-    let to_check = deps_of(metadata, &krate.id);
-
-    for dep in to_check {
-        let mut bad = check_crate_dependencies(permitted_dependencies, metadata, visited, dep);
-        unapproved.append(&mut bad);
-    }
-
-    unapproved
 }
 
 /// Prevents multiple versions of some expensive crates.
@@ -588,24 +552,6 @@ fn check_crate_duplicate(
     }
 }
 
-/// Returns a list of dependencies for the given package.
-fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> {
-    let resolve = metadata.resolve.as_ref().unwrap();
-    let node = resolve
-        .nodes
-        .iter()
-        .find(|n| &n.id == pkg_id)
-        .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
-    node.deps
-        .iter()
-        .map(|dep| {
-            metadata.packages.iter().find(|pkg| pkg.id == dep.pkg).unwrap_or_else(|| {
-                panic!("could not find dep `{}` for pkg `{}` in resolve", dep.pkg, pkg_id)
-            })
-        })
-        .collect()
-}
-
 /// Finds a package with the given name.
 fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
     let mut i = metadata.packages.iter().filter(|p| p.name == name);
@@ -615,41 +561,57 @@ fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package
     result
 }
 
+fn pkg_from_id<'a>(metadata: &'a Metadata, id: &PackageId) -> &'a Package {
+    metadata.packages.iter().find(|p| &p.id == id).unwrap()
+}
+
 /// Finds all the packages that are in the rust runtime.
 fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId> {
-    let resolve = metadata.resolve.as_ref().unwrap();
     let mut result = HashSet::new();
     for name in RUNTIME_CRATES {
         let id = &pkg_from_name(metadata, name).id;
-        normal_deps_of_r(resolve, id, &mut result);
+        deps_of_filtered(metadata, id, &mut result, &|_| true);
     }
     result
 }
 
-/// Recursively find all normal dependencies.
-fn normal_deps_of_r<'a>(
-    resolve: &'a Resolve,
+/// Recursively find all dependencies.
+fn deps_of_filtered<'a>(
+    metadata: &'a Metadata,
     pkg_id: &'a PackageId,
     result: &mut HashSet<&'a PackageId>,
+    filter: &dyn Fn(&[DepKindInfo]) -> bool,
 ) {
     if !result.insert(pkg_id) {
         return;
     }
-    let node = resolve
+    let node = metadata
+        .resolve
+        .as_ref()
+        .unwrap()
         .nodes
         .iter()
         .find(|n| &n.id == pkg_id)
         .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
     for dep in &node.deps {
-        normal_deps_of_r(resolve, &dep.pkg, result);
+        if !filter(&dep.dep_kinds) {
+            continue;
+        }
+        deps_of_filtered(metadata, &dep.pkg, result, filter);
     }
 }
 
+fn direct_deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> {
+    let resolve = metadata.resolve.as_ref().unwrap();
+    let node = resolve.nodes.iter().find(|n| &n.id == pkg_id).unwrap();
+    node.deps.iter().map(|dep| pkg_from_id(metadata, &dep.pkg)).collect()
+}
+
 fn check_rustfix(metadata: &Metadata, bad: &mut bool) {
     let cargo = pkg_from_name(metadata, "cargo");
     let compiletest = pkg_from_name(metadata, "compiletest");
-    let cargo_deps = deps_of(metadata, &cargo.id);
-    let compiletest_deps = deps_of(metadata, &compiletest.id);
+    let cargo_deps = direct_deps_of(metadata, &cargo.id);
+    let compiletest_deps = direct_deps_of(metadata, &compiletest.id);
     let cargo_rustfix = cargo_deps.iter().find(|p| p.name == "rustfix").unwrap();
     let compiletest_rustfix = compiletest_deps.iter().find(|p| p.name == "rustfix").unwrap();
     if cargo_rustfix.version != compiletest_rustfix.version {
index bc9fd35ecde3786c2db4092104dce15e25d69290..6bb4d32f87d0a25bd2b5a065741ce3e3fc5e6cb8 100644 (file)
 const ERROR_TESTS_PATH: &str = "tests/ui/error-codes/";
 
 // Error codes that (for some reason) can't have a doctest in their explanation. Error codes are still expected to provide a code example, even if untested.
-const IGNORE_DOCTEST_CHECK: &[&str] =
-    &["E0208", "E0464", "E0570", "E0601", "E0602", "E0640", "E0717"];
+const IGNORE_DOCTEST_CHECK: &[&str] = &["E0464", "E0570", "E0601", "E0602", "E0640", "E0717"];
 
 // Error codes that don't yet have a UI test. This list will eventually be removed.
 const IGNORE_UI_TEST_CHECK: &[&str] =
-    &["E0461", "E0465", "E0476", "E0514", "E0523", "E0554", "E0640", "E0717", "E0729", "E0789"];
+    &["E0461", "E0465", "E0476", "E0514", "E0523", "E0554", "E0640", "E0717", "E0729"];
 
 macro_rules! verbose_print {
     ($verbose:expr, $($fmt:tt)*) => {
index 40375f1306d629700f41b8e81369de264d843636..35000320d1abfcbe24610b55ab4a5df2f5f82a76 100644 (file)
@@ -62,6 +62,7 @@ fn tidy_error(bad: &mut bool, args: impl Display) -> std::io::Result<()> {
 pub mod mir_opt_tests;
 pub mod pal;
 pub mod primitive_docs;
+pub mod rustdoc_gui_tests;
 pub mod style;
 pub mod target_specific_tests;
 pub mod tests_placement;
@@ -69,3 +70,4 @@ fn tidy_error(bad: &mut bool, args: impl Display) -> std::io::Result<()> {
 pub mod unit_tests;
 pub mod unstable_book;
 pub mod walk;
+pub mod x_version;
index ea2886a3c2f8fda013abaf1c581a466939f36694..505f9d724c8d3d450eae9115f271c6726106c497 100644 (file)
@@ -60,7 +60,7 @@ macro_rules! check {
 
                 let handle = s.spawn(|| {
                     let mut flag = false;
-                    $p::check($($args),* , &mut flag);
+                    $p::check($($args, )* &mut flag);
                     if (flag) {
                         bad.store(true, Ordering::Relaxed);
                     }
@@ -80,6 +80,7 @@ macro_rules! check {
         check!(debug_artifacts, &tests_path);
         check!(ui_tests, &tests_path);
         check!(mir_opt_tests, &tests_path, bless);
+        check!(rustdoc_gui_tests, &tests_path);
 
         // Checks that only make sense for the compiler.
         check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
@@ -113,6 +114,8 @@ macro_rules! check {
         check!(alphabetical, &compiler_path);
         check!(alphabetical, &library_path);
 
+        check!(x_version, &root_path, &cargo);
+
         let collected = {
             drain_handles(&mut handles);
 
diff --git a/src/tools/tidy/src/rustdoc_gui_tests.rs b/src/tools/tidy/src/rustdoc_gui_tests.rs
new file mode 100644 (file)
index 0000000..feb513d
--- /dev/null
@@ -0,0 +1,33 @@
+//! Tidy check to ensure that rustdoc GUI tests start with a small description.
+
+use std::path::Path;
+
+pub fn check(path: &Path, bad: &mut bool) {
+    crate::walk::walk(
+        &path.join("rustdoc-gui"),
+        &mut |p| {
+            // If there is no extension, it's very likely a folder and we want to go into it.
+            p.extension().map(|e| e != "goml").unwrap_or(false)
+        },
+        &mut |entry, content| {
+            for line in content.lines() {
+                if !line.starts_with("// ") {
+                    tidy_error!(
+                        bad,
+                        "{}: rustdoc-gui tests must start with a small description",
+                        entry.path().display(),
+                    );
+                    return;
+                } else if line.starts_with("// ") {
+                    let parts = line[2..].trim();
+                    // We ignore tidy comments.
+                    if parts.starts_with("// tidy-") {
+                        continue;
+                    }
+                    // All good!
+                    return;
+                }
+            }
+        },
+    );
+}
index 5c4ba86936456f683e6dd5386be061cba7ec57f2..6a0855405ec90bb491547aa8e34a9bc6b4755e2d 100644 (file)
@@ -45,6 +45,9 @@
 when executed when assertions are disabled.
 Use llvm::report_fatal_error for increased robustness.";
 
+const DOUBLE_SPACE_AFTER_DOT: &str = r"\
+Use a single space after dots in comments.";
+
 const ANNOTATIONS_TO_IGNORE: &[&str] = &[
     "// @!has",
     "// @has",
@@ -279,6 +282,10 @@ fn skip(path: &Path) -> bool {
         if filename.contains("ignore-tidy") {
             return;
         }
+        // apfloat shouldn't be changed because of license problems
+        if is_in(file, "compiler", "rustc_apfloat") {
+            return;
+        }
         let mut skip_cr = contains_ignore_directive(can_contain, &contents, "cr");
         let mut skip_undocumented_unsafe =
             contains_ignore_directive(can_contain, &contents, "undocumented-unsafe");
@@ -405,6 +412,19 @@ fn skip(path: &Path) -> bool {
             if filename.ends_with(".cpp") && line.contains("llvm_unreachable") {
                 err(LLVM_UNREACHABLE_INFO);
             }
+
+            // For now only enforce in compiler
+            let is_compiler = || file.components().any(|c| c.as_os_str() == "compiler");
+            if is_compiler()
+                && line.contains("//")
+                && line
+                    .chars()
+                    .collect::<Vec<_>>()
+                    .windows(4)
+                    .any(|cs| matches!(cs, ['.', ' ', ' ', last] if last.is_alphabetic()))
+            {
+                err(DOUBLE_SPACE_AFTER_DOT)
+            }
         }
         if leading_new_lines {
             let mut err = |_| {
diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
new file mode 100644 (file)
index 0000000..c470d50
--- /dev/null
@@ -0,0 +1,68 @@
+use semver::Version;
+use std::path::Path;
+use std::process::{Command, Stdio};
+
+pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
+    let cargo_list = Command::new(cargo).args(["install", "--list"]).stdout(Stdio::piped()).spawn();
+
+    let child = match cargo_list {
+        Ok(child) => child,
+        Err(e) => return tidy_error!(bad, "failed to run `cargo`: {}", e),
+    };
+
+    let cargo_list = child.wait_with_output().unwrap();
+
+    if cargo_list.status.success() {
+        let exe_list = String::from_utf8_lossy(&cargo_list.stdout);
+        let exe_list = exe_list.lines();
+
+        let mut installed: Option<Version> = None;
+
+        for line in exe_list {
+            let mut iter = line.split_whitespace();
+            if iter.next() == Some("x") {
+                if let Some(version) = iter.next() {
+                    // Check this is the rust-lang/rust x tool installation since it should be
+                    // installed at a path containing `src/tools/x`.
+                    if let Some(path) = iter.next() {
+                        if path.contains(&"src/tools/x") {
+                            let version = version.strip_prefix("v").unwrap();
+                            installed = Some(Version::parse(version).unwrap());
+                            break;
+                        }
+                    };
+                }
+            } else {
+                continue;
+            }
+        }
+        // Unwrap the some if x is installed, otherwise return because it's fine if x isn't installed.
+        let installed = if let Some(i) = installed { i } else { return };
+
+        if let Some(expected) = get_x_wrapper_version(root, cargo) {
+            if installed < expected {
+                return println!(
+                    "Current version of x is {installed}, but the latest version is {expected}\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+                );
+            }
+        } else {
+            return tidy_error!(
+                bad,
+                "Unable to parse the latest version of `x` at `src/tools/x/Cargo.toml`"
+            );
+        }
+    } else {
+        return tidy_error!(bad, "failed to check version of `x`: {}", cargo_list.status);
+    }
+}
+
+// Parse latest version out of `x` Cargo.toml
+fn get_x_wrapper_version(root: &Path, cargo: &Path) -> Option<Version> {
+    let mut cmd = cargo_metadata::MetadataCommand::new();
+    cmd.cargo_path(cargo)
+        .manifest_path(root.join("src/tools/x/Cargo.toml"))
+        .no_deps()
+        .features(cargo_metadata::CargoOpt::AllFeatures);
+    let mut metadata = t!(cmd.exec());
+    metadata.packages.pop().map(|x| x.version)
+}
index ee2f4ca913048744aab4763a96594995e832c29a..49349856550b67391da4db65f04579adf8044003 100644 (file)
@@ -1 +1 @@
-1.68.0
+1.69.0
index 04b5de83423709c09a5980b1ec645712715956bb..620a3da94636e80b010ba0fe6dd4d8f897fe9574 100644 (file)
@@ -1,5 +1,5 @@
 // assembly-output: emit-asm
-// min-llvm-version: 14.0
+// min-llvm-version: 15.0
 // only-x86_64
 // revisions: opt-speed opt-size
 // [opt-speed] compile-flags: -Copt-level=1
index dfc312279083d6fe576440b4e6fa7bb796651ec0..3c2d4e719d423f9a309064cb688d0419f9b25a59 100644 (file)
@@ -3,7 +3,7 @@
 // of the sysv64 abi.
 //
 // needs-llvm-components: x86
-// compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu
+// compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu -Copt-level=0
 
 #![crate_type = "lib"]
 #![no_core]
index d612f603e4fea0d27e64b0e4f17b914f565a195d..928ad5a9bbd6376d493b902cbc6dabdb1c0ff909 100644 (file)
@@ -3,7 +3,7 @@
 // of the x86-interrupt abi.
 
 // needs-llvm-components: x86
-// compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu
+// compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu -Copt-level=0
 
 #![crate_type = "lib"]
 #![no_core]
index 39880c9341f4f96aea9585835053c12f00f93775..6d22475175270570f022bd0816bf3d18dd594007 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -C no-prepopulate-passes
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
 
 #![crate_type = "lib"]
 
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))
+}
index 7b5ae894311eff15f8d2e9184a23fbe426a230ac..b0c88f76c436dc9067dad98b7ebad22902b4983a 100644 (file)
@@ -31,4 +31,4 @@ pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
 // Hide the LLVM 15+ `allocalign` attribute in the declaration of __rust_alloc
 // from the CHECK-NOT above. We don't check the attributes here because we can't rely
 // on all of them being set until LLVM 15.
-// CHECK: declare noalias{{.*}} @__rust_alloc(i{{[0-9]+}}, i{{[0-9]+.*}})
+// CHECK: declare noalias{{.*}} @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+.*}} noundef)
index c82b56a71f5cfde9d3c9a90f2143841536110119..2f88966996ab2e25efb1adfcb8d03420d3cf5e5d 100644 (file)
@@ -28,6 +28,6 @@ pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
 
 // Hide the `allocalign` attribute in the declaration of __rust_alloc
 // from the CHECK-NOT above, and also verify the attributes got set reasonably.
-// CHECK: declare noalias ptr @__rust_alloc(i{{[0-9]+}}, i{{[0-9]+}} allocalign) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]]
+// CHECK: declare noalias noundef ptr @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]]
 
 // CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} }
index a5be56c47be81e131c5ec114531dbc4f56f76804..cab32652210d0a08188e870c3c893267fa29191f 100644 (file)
@@ -1,5 +1,5 @@
 // ignore-wasm32-bare compiled with panic=abort by default
-// compile-flags: -C no-prepopulate-passes
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
 //
 
 #![crate_type = "lib"]
index 998099c23909855e163986cbd410adc5828307c7..cb8abae198ee65b9315f9d1a1d827605f8512400 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -C no-prepopulate-passes
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
 
 // ignore-riscv64
 
index 5cf6c3ac0a2333f55db87a00349ae93ae0ee9fef..683a2bd4fbb5a8abb5f68bd1cb944dc60f45c43d 100644 (file)
@@ -13,7 +13,7 @@
 pub struct Foo(u16);
 
 // CHECK-LABEL: @check_lt
-// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]])
+// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
 #[no_mangle]
 pub fn check_lt(a: Foo, b: Foo) -> bool {
     // CHECK: %[[R:.+]] = icmp ult i16 %[[A]], %[[B]]
@@ -22,7 +22,7 @@ pub fn check_lt(a: Foo, b: Foo) -> bool {
 }
 
 // CHECK-LABEL: @check_le
-// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]])
+// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
 #[no_mangle]
 pub fn check_le(a: Foo, b: Foo) -> bool {
     // CHECK: %[[R:.+]] = icmp ule i16 %[[A]], %[[B]]
@@ -31,7 +31,7 @@ pub fn check_le(a: Foo, b: Foo) -> bool {
 }
 
 // CHECK-LABEL: @check_gt
-// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]])
+// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
 #[no_mangle]
 pub fn check_gt(a: Foo, b: Foo) -> bool {
     // CHECK: %[[R:.+]] = icmp ugt i16 %[[A]], %[[B]]
@@ -40,7 +40,7 @@ pub fn check_gt(a: Foo, b: Foo) -> bool {
 }
 
 // CHECK-LABEL: @check_ge
-// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]])
+// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
 #[no_mangle]
 pub fn check_ge(a: Foo, b: Foo) -> bool {
     // CHECK: %[[R:.+]] = icmp uge i16 %[[A]], %[[B]]
index bdd312878ec887bb5ade80915bdde69fce5060f7..d82b737de0b417c5dd6c31288ef0edfc594205b8 100644 (file)
@@ -9,6 +9,14 @@
 // compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0
 // ignore-tidy-linelength
 
+// Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled.
+// This helps debuggers more reliably map from dyn pointer to concrete type.
+// CHECK: @vtable.0 = private constant <{
+// CHECK: @vtable.1 = private constant <{
+// CHECK: @vtable.2 = private constant <{
+// CHECK: @vtable.3 = private constant <{
+// CHECK: @vtable.4 = private constant <{
+
 // NONMSVC: ![[USIZE:[0-9]+]] = !DIBasicType(name: "usize"
 // MSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize"
 // NONMSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()"
index ab599992ffd79d70de76b07846caf2c999cc7567..383940e95906d1c6dad3db944243ae674e98cb35 100644 (file)
@@ -1,4 +1,4 @@
-// This test is for *-windows-msvc only.
+ // This test is for *-windows-msvc only.
 // only-windows
 // ignore-gnu
 
 // CHECK: @static_global1 = external local_unnamed_addr global i32
 // CHECK: @static_global2 = external local_unnamed_addr global i32
 
-// CHECK: declare dllimport i32 @dylib_func1(i32)
-// CHECK: declare dllimport i32 @dylib_func2(i32)
-// CHECK: declare i32 @static_func1(i32)
-// CHECK: declare i32 @static_func2(i32)
+// CHECK: declare dllimport noundef i32 @dylib_func1(i32 noundef)
+// CHECK: declare dllimport noundef i32 @dylib_func2(i32 noundef)
+// CHECK: declare noundef i32 @static_func1(i32 noundef)
+// CHECK: declare noundef i32 @static_func2(i32 noundef)
 
 #[link(name = "dummy", kind="dylib")]
 extern "C" {
index 827eb20154afd0195cc1da957b67aa483444f56b..5f8063a27f7ac7355927906e2756a2ea2ae96fd8 100644 (file)
@@ -11,7 +11,7 @@ pub enum Enum0 {
     B,
 }
 
-// CHECK: define i8 @match0{{.*}}
+// CHECK: define noundef i8 @match0{{.*}}
 // CHECK-NEXT: start:
 // CHECK-NEXT: %1 = icmp eq i8 %0, 2
 // CHECK-NEXT: %2 = and i8 %0, 1
@@ -32,7 +32,7 @@ pub enum Enum1 {
     C,
 }
 
-// CHECK: define i8 @match1{{.*}}
+// CHECK: define noundef i8 @match1{{.*}}
 // CHECK-NEXT: start:
 // CHECK-NEXT: [[DISCR:%.*]] = {{.*}}call i8 @llvm.usub.sat.i8(i8 %0, i8 1)
 // CHECK-NEXT: switch i8 [[DISCR]], label {{.*}} [
@@ -88,7 +88,7 @@ pub enum Enum2 {
     E,
 }
 
-// CHECK: define i8 @match2{{.*}}
+// CHECK: define noundef i8 @match2{{.*}}
 // CHECK-NEXT: start:
 // CHECK-NEXT: %1 = add i8 %0, 2
 // CHECK-NEXT: %2 = zext i8 %1 to i64
index d426ade28dd12696dd41073ef60b46ff526f8793..02f5d545910e1f7f2e12dc2e150a71ff62bb3771 100644 (file)
@@ -15,27 +15,27 @@ trait Sized {}
 trait Copy {}
 
 pub mod tests {
-    // CHECK: @f1(i32 inreg %_1, i32 inreg %_2, i32 %_3)
+    // CHECK: @f1(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3)
     #[no_mangle]
     pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {}
 
-    // CHECK: @f2({{i32\*|ptr}} inreg %_1, {{i32\*|ptr}} inreg %_2, {{i32\*|ptr}} %_3)
+    // CHECK: @f2({{i32\*|ptr}} inreg noundef %_1, {{i32\*|ptr}} inreg noundef %_2, {{i32\*|ptr}} noundef %_3)
     #[no_mangle]
     pub extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {}
 
-    // CHECK: @f3(float %_1, i32 inreg %_2, i32 inreg %_3, i32 %_4)
+    // CHECK: @f3(float noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3, i32 noundef %_4)
     #[no_mangle]
     pub extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {}
 
-    // CHECK: @f4(i32 inreg %_1, float %_2, i32 inreg %_3, i32 %_4)
+    // CHECK: @f4(i32 inreg noundef %_1, float noundef %_2, i32 inreg noundef %_3, i32 noundef %_4)
     #[no_mangle]
     pub extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {}
 
-    // CHECK: @f5(i64 %_1, i32 %_2)
+    // CHECK: @f5(i64 noundef %_1, i32 noundef %_2)
     #[no_mangle]
     pub extern "fastcall" fn f5(_: i64, _: i32) {}
 
-    // CHECK: @f6(i1 inreg noundef zeroext %_1, i32 inreg %_2, i32 %_3)
+    // CHECK: @f6(i1 inreg noundef zeroext %_1, i32 inreg noundef %_2, i32 noundef %_3)
     #[no_mangle]
     pub extern "fastcall" fn f6(_: bool, _: i32, _: i32) {}
 }
index 7307e0379dfa042eb02b7484b556f2393b61c590..ac8cba06b48f7616f3450e5b6e2630c2ed84bfd2 100644 (file)
@@ -7,11 +7,11 @@
 
 #[no_mangle]
 pub fn sum(x: u32, y: u32) -> u32 {
-// YES-LABEL: define{{.*}}i32 @sum(i32 %0, i32 %1)
+// YES-LABEL: define{{.*}}i32 @sum(i32 noundef %0, i32 noundef %1)
 // YES-NEXT:    %3 = add i32 %1, %0
 // YES-NEXT:    ret i32 %3
 
-// NO-LABEL: define{{.*}}i32 @sum(i32 %x, i32 %y)
+// NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y)
 // NO-NEXT:  start:
 // NO-NEXT:    %z = add i32 %y, %x
 // NO-NEXT:    ret i32 %z
index f7c02d47939fed4314f87dde85ba35526761d7da..d8933262e528e98cc4522726d43b1fff87176257 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: --crate-type=rlib
+// compile-flags: --crate-type=rlib -Copt-level=0
 // revisions: aarch64-apple aarch64-linux force x64-apple x64-linux
 // [aarch64-apple] needs-llvm-components: aarch64
 // [aarch64-apple] compile-flags: --target=aarch64-apple-darwin
index 0f9e90f6ba77990d2c265057699170a5cd372dbe..1f979d7b90a70b08b7a5edd95028777218481772 100644 (file)
@@ -1,11 +1,11 @@
 // compile-flags: -O -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(rustc_attrs)]
 
 use std::mem::MaybeUninit;
 use std::num::NonZeroU64;
 use std::marker::PhantomPinned;
+use std::ptr::NonNull;
 
 pub struct S {
   _field: [i32; 8],
@@ -61,7 +61,7 @@ pub fn maybeuninit_char(x: MaybeUninit<char>) -> MaybeUninit<char> {
   x
 }
 
-// CHECK: i64 @int(i64 %x)
+// CHECK: noundef i64 @int(i64 noundef %x)
 #[no_mangle]
 pub fn int(x: u64) -> u64 {
   x
@@ -73,7 +73,7 @@ pub fn nonzero_int(x: NonZeroU64) -> NonZeroU64 {
   x
 }
 
-// CHECK: i64 @option_nonzero_int(i64 %x)
+// CHECK: noundef i64 @option_nonzero_int(i64 noundef %x)
 #[no_mangle]
 pub fn option_nonzero_int(x: Option<NonZeroU64>) -> Option<NonZeroU64> {
   x
@@ -138,11 +138,27 @@ pub fn indirect_struct(_: S) {
 pub fn borrowed_struct(_: &S) {
 }
 
-// CHECK: @raw_struct({{%S\*|ptr}} %_1)
+// CHECK: @option_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable_or_null(4) %x)
+#[no_mangle]
+pub fn option_borrow(x: Option<&i32>) {
+}
+
+// CHECK: @option_borrow_mut({{i32\*|ptr}} noalias noundef align 4 dereferenceable_or_null(4) %x)
+#[no_mangle]
+pub fn option_borrow_mut(x: Option<&mut i32>) {
+}
+
+// CHECK: @raw_struct({{%S\*|ptr}} noundef %_1)
 #[no_mangle]
 pub fn raw_struct(_: *const S) {
 }
 
+// CHECK: @raw_option_nonnull_struct({{i32\*|ptr}} noundef %_1)
+#[no_mangle]
+pub fn raw_option_nonnull_struct(_: Option<NonNull<S>>) {
+}
+
+
 // `Box` can get deallocated during execution of the function, so it should
 // not get `dereferenceable`.
 // CHECK: noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
@@ -160,35 +176,35 @@ pub fn struct_return() -> S {
 }
 
 // Hack to get the correct size for the length part in slices
-// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
+// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1)
 #[no_mangle]
 pub fn helper(_: usize) {
 }
 
-// CHECK: @slice({{\[0 x i8\]\*|ptr}} noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1)
+// CHECK: @slice({{\[0 x i8\]\*|ptr}} noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn slice(_: &[u8]) {
 }
 
-// CHECK: @mutable_slice({{\[0 x i8\]\*|ptr}} noalias noundef nonnull align 1 %_1.0, [[USIZE]] %_1.1)
+// CHECK: @mutable_slice({{\[0 x i8\]\*|ptr}} noalias noundef nonnull align 1 %_1.0, [[USIZE]] noundef %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn mutable_slice(_: &mut [u8]) {
 }
 
-// CHECK: @unsafe_slice({{\[0 x i16\]\*|ptr}} noundef nonnull align 2 %_1.0, [[USIZE]] %_1.1)
+// CHECK: @unsafe_slice({{\[0 x i16\]\*|ptr}} noundef nonnull align 2 %_1.0, [[USIZE]] noundef %_1.1)
 // unsafe interior means this isn't actually readonly and there may be aliases ...
 #[no_mangle]
 pub fn unsafe_slice(_: &[UnsafeInner]) {
 }
 
-// CHECK: @raw_slice({{\[0 x i8\]\*|ptr}} %_1.0, [[USIZE]] %_1.1)
+// CHECK: @raw_slice({{\[0 x i8\]\*|ptr}} noundef %_1.0, [[USIZE]] noundef %_1.1)
 #[no_mangle]
 pub fn raw_slice(_: *const [u8]) {
 }
 
-// CHECK: @str({{\[0 x i8\]\*|ptr}} noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1)
+// CHECK: @str({{\[0 x i8\]\*|ptr}} noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn str(_: &[u8]) {
@@ -197,26 +213,36 @@ pub fn str(_: &[u8]) {
 // CHECK: @trait_borrow({{\{\}\*|ptr}} noundef nonnull align 1 %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
-pub fn trait_borrow(_: &Drop) {
+pub fn trait_borrow(_: &dyn Drop) {
+}
+
+// CHECK: @option_trait_borrow({{i8\*|ptr}} noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
+#[no_mangle]
+pub fn option_trait_borrow(x: Option<&dyn Drop>) {
+}
+
+// CHECK: @option_trait_borrow_mut({{i8\*|ptr}} noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
+#[no_mangle]
+pub fn option_trait_borrow_mut(x: Option<&mut dyn Drop>) {
 }
 
-// CHECK: @trait_raw({{\{\}\*|ptr}} %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
+// CHECK: @trait_raw({{\{\}\*|ptr}} noundef %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
 #[no_mangle]
-pub fn trait_raw(_: *const Drop) {
+pub fn trait_raw(_: *const dyn Drop) {
 }
 
 // CHECK: @trait_box({{\{\}\*|ptr}} noalias noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}})
 #[no_mangle]
-pub fn trait_box(_: Box<Drop>) {
+pub fn trait_box(_: Box<dyn Drop>) {
 }
 
 // CHECK: { {{i8\*|ptr}}, {{i8\*|ptr}} } @trait_option({{i8\*|ptr}} noalias noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
 #[no_mangle]
-pub fn trait_option(x: Option<Box<Drop>>) -> Option<Box<Drop>> {
+pub fn trait_option(x: Option<Box<dyn Drop>>) -> Option<Box<dyn Drop>> {
   x
 }
 
-// CHECK: { {{\[0 x i16\]\*|ptr}}, [[USIZE]] } @return_slice({{\[0 x i16\]\*|ptr}} noalias noundef nonnull readonly align 2 %x.0, [[USIZE]] %x.1)
+// CHECK: { {{\[0 x i16\]\*|ptr}}, [[USIZE]] } @return_slice({{\[0 x i16\]\*|ptr}} noalias noundef nonnull readonly align 2 %x.0, [[USIZE]] noundef %x.1)
 #[no_mangle]
 pub fn return_slice(x: &[u16]) -> &[u16] {
   x
index db8a04763d35dc0ac3242b8b20e02ff16f2f8b05..f3877dc6b96a68e2efe69158dcaad271eab83690 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -C no-prepopulate-passes
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
 
 #![crate_type = "lib"]
 #![feature(const_eval_select)]
index 2e984db1be528d30e5a97c25fb4f5d5f8b0930c3..8f93da2e5da437f616250d863f23d71b8c24c8de 100644 (file)
@@ -1,3 +1,4 @@
+// compile-flags: -Copt-level=0
 #![crate_type = "lib"]
 #![feature(core_intrinsics)]
 
@@ -6,6 +7,6 @@
 #[no_mangle]
 pub fn mask_ptr(ptr: *const u16, mask: usize) -> *const u16 {
     // CHECK: call
-    // CHECK-SAME: @llvm.ptrmask.{{p0|p0i8}}.[[WORD]]({{ptr|i8\*}} {{%ptr|%0}}, [[WORD]] %mask)
+    // CHECK-SAME: @llvm.ptrmask.{{p0|p0i8}}.[[WORD]]({{ptr|i8\*}} {{%ptr|%1}}, [[WORD]] %mask)
     core::intrinsics::ptr_mask(ptr, mask)
 }
index 82ba325572ab45ddfb5da2c1ef516860c1641f91..abef92c19b610b612da29d6c5fbad049c2ddd695 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -C no-prepopulate-passes
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
 
 #![crate_type = "lib"]
 
index aa59c713b7846dabbb55cce82be977b148eb91f8..1daa213fc821392f6ebefe5ce99ca36387af7c17 100644 (file)
@@ -2,6 +2,7 @@
 // prevent optimizing away bounds checks
 
 // compile-flags: -O
+// ignore-debug: the debug assertions get in the way
 
 #![crate_type="rlib"]
 
index 0900a33377bcdc41993464d83fb5043e9bccde70..00f8953d94952f1c1ec7a521f49510c09b1d8acb 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -C no-prepopulate-passes
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
 //
 // only-x86_64
 // ignore-windows
index a5dbef93460272a18a8c9857fc0df95bc7bf90e8..0413ed6b26f360d59817257595f0bfac463b46bc 100644 (file)
@@ -3,7 +3,7 @@
 // in some situations, see https://github.com/rust-lang/rust/issues/96497#issuecomment-1112865218
 
 // compile-flags: -O
-// min-llvm-version: 14.0
+// min-llvm-version: 15.0
 
 #![crate_type="lib"]
 
index 20e1d9b4d5988daf60977e13b4aabdc23a952e66..24059f190acf608944117454013e8a33d7ee1429 100644 (file)
@@ -46,7 +46,7 @@ pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN<NotCopy>) -> Option<NotCop
 #[no_mangle]
 // CHECK-LABEL: @vec_extend_via_iter_repeat_n
 pub fn vec_extend_via_iter_repeat_n() -> Vec<u8> {
-    // CHECK: %[[ADDR:.+]] = tail call dereferenceable_or_null(1234) ptr @__rust_alloc(i64 1234, i64 1)
+    // CHECK: %[[ADDR:.+]] = tail call noundef dereferenceable_or_null(1234) ptr @__rust_alloc(i64 noundef 1234, i64 noundef 1)
     // CHECK: tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(1234) %[[ADDR]], i8 42, i64 1234,
 
     let n = 1234_usize;
index f448306ba1b086fd7157cff68a5e667c0694d400..f29a26596bfd5a8af36962e3e3ad6fa9e4244fc5 100644 (file)
@@ -50,8 +50,8 @@ pub fn load_scalar_pair<'a>(x: &(&'a i32, &'a Align16)) -> (&'a i32, &'a Align16
 // CHECK-LABEL: @load_raw_pointer
 #[no_mangle]
 pub fn load_raw_pointer<'a>(x: &*const i32) -> *const i32 {
-    // loaded raw pointer should not have !nonnull, !align, or !noundef metadata
-    // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %x, align [[PTR_ALIGNMENT]]{{$}}
+    // loaded raw pointer should not have !nonnull or !align metadata
+    // CHECK: load {{i32\*|ptr}}, {{i32\*\*|ptr}} %x, align [[PTR_ALIGNMENT]], !noundef ![[NOUNDEF:[0-9]+]]{{$}}
     *x
 }
 
@@ -93,7 +93,7 @@ pub fn load_maybeuninit_enum_bool(x: &MaybeUninit<MyBool>) -> MaybeUninit<MyBool
 // CHECK-LABEL: @load_int
 #[no_mangle]
 pub fn load_int(x: &u16) -> u16 {
-    // CHECK: load i16, {{i16\*|ptr}} %x, align 2{{$}}
+    // CHECK: load i16, {{i16\*|ptr}} %x, align 2, !noundef ![[NOUNDEF]]{{$}}
     *x
 }
 
@@ -107,7 +107,7 @@ pub fn load_nonzero_int(x: &NonZeroU16) -> NonZeroU16 {
 // CHECK-LABEL: @load_option_nonzero_int
 #[no_mangle]
 pub fn load_option_nonzero_int(x: &Option<NonZeroU16>) -> Option<NonZeroU16> {
-    // CHECK: load i16, {{i16\*|ptr}} %x, align 2{{$}}
+    // CHECK: load i16, {{i16\*|ptr}} %x, align 2, !noundef ![[NOUNDEF]]{{$}}
     *x
 }
 
index 51c7a0c615d00d321c39578ade27990b55d5879b..e05bbc26e830c33d43db8295fb5a0709eab735ed 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -C no-prepopulate-passes
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
 // needs-asm-support
 // only-x86_64
 
index 598dcc19b491bf9ec70847514ae327ed2362a903..835decd3e5f5e488f98693f3b8aa3acbffd857d2 100644 (file)
@@ -3,6 +3,7 @@
 #![crate_type = "lib"]
 
 extern crate core;
+use core::cmp::Ordering;
 use core::num::{NonZeroU32, NonZeroI64};
 use core::ptr::NonNull;
 
@@ -32,3 +33,12 @@ pub fn non_null_eq(l: Option<NonNull<u8>>, r: Option<NonNull<u8>>) -> bool {
     // CHECK-NEXT: ret i1
     l == r
 }
+
+// CHECK-lABEL: @ordering_eq
+#[no_mangle]
+pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool {
+    // CHECK: start:
+    // CHECK-NEXT: icmp eq i8
+    // CHECK-NEXT: ret i1
+    l == r
+}
index 602a08067bae183cd1e489d24e3801d052421017..518e949ffe34386cb1446ee1082eb6f1ea9de6d5 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -C relocation-model=pic
+// compile-flags: -C relocation-model=pic -Copt-level=0
 
 #![crate_type = "rlib"]
 
index ec44edc0667741ad863b968aa99141a040f77963..941cca922bd328de6f23e25aceea3d69128e7e6c 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -C relocation-model=pie
+// compile-flags: -C relocation-model=pie -Copt-level=0
 // only-x86_64-unknown-linux-gnu
 
 #![crate_type = "rlib"]
index 0b796754d1d861f8c15b6387d181827c03bd0f2d..a528976671110963852af8779e27dcaa8c2fda44 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0
+// compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 -Copt-level=0
 
 #![crate_type = "lib"]
 
index 4f2313ce47a979be33140172948c254831e8b538..311cbfbaa09372915dba17b5b1125ec36d9ae2c0 100644 (file)
 #[repr(transparent)]
 pub struct F32(f32);
 
-// CHECK: define{{.*}}float @test_F32(float %_1)
+// CHECK: define{{.*}}float @test_F32(float noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_F32(_: F32) -> F32 { loop {} }
 
 #[repr(transparent)]
 pub struct Ptr(*mut u8);
 
-// CHECK: define{{.*}}{{i8\*|ptr}} @test_Ptr({{i8\*|ptr}} %_1)
+// CHECK: define{{.*}}{{i8\*|ptr}} @test_Ptr({{i8\*|ptr}} noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_Ptr(_: Ptr) -> Ptr { loop {} }
 
 #[repr(transparent)]
 pub struct WithZst(u64, Zst1);
 
-// CHECK: define{{.*}}i64 @test_WithZst(i64 %_1)
+// CHECK: define{{.*}}i64 @test_WithZst(i64 noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_WithZst(_: WithZst) -> WithZst { loop {} }
 
@@ -40,14 +40,14 @@ pub extern "C" fn test_WithZst(_: WithZst) -> WithZst { loop {} }
 pub struct WithZeroSizedArray(*const f32, [i8; 0]);
 
 // Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever.
-// CHECK: define{{.*}}{{i32\*|ptr}} @test_WithZeroSizedArray({{i32\*|ptr}} %_1)
+// CHECK: define{{.*}}{{i32\*|ptr}} @test_WithZeroSizedArray({{i32\*|ptr}} noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} }
 
 #[repr(transparent)]
 pub struct Generic<T>(T);
 
-// CHECK: define{{.*}}double @test_Generic(double %_1)
+// CHECK: define{{.*}}double @test_Generic(double noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_Generic(_: Generic<f64>) -> Generic<f64> { loop {} }
 
@@ -64,7 +64,7 @@ pub extern "C" fn test_Gpz(_: GenericPlusZst<Bool>) -> GenericPlusZst<Bool> { lo
 #[repr(transparent)]
 pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>);
 
-// CHECK: define{{.*}}{{i16\*|ptr}} @test_LifetimePhantom({{i16\*|ptr}} %_1)
+// CHECK: define{{.*}}{{i16\*|ptr}} @test_LifetimePhantom({{i16\*|ptr}} noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_LifetimePhantom(_: LifetimePhantom<i16>) -> LifetimePhantom<i16> { loop {} }
 
@@ -74,28 +74,28 @@ pub struct UnitPhantom<T, U> { val: T, unit: PhantomData<U> }
 
 pub struct Px;
 
-// CHECK: define{{.*}}float @test_UnitPhantom(float %_1)
+// CHECK: define{{.*}}float @test_UnitPhantom(float noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_UnitPhantom(_: UnitPhantom<f32, Px>) -> UnitPhantom<f32, Px> { loop {} }
 
 #[repr(transparent)]
 pub struct TwoZsts(Zst1, i8, Zst2);
 
-// CHECK: define{{( dso_local)?}}{{( signext)?}} i8 @test_TwoZsts(i8{{( signext)?}} %_1)
+// CHECK: define{{( dso_local)?}} noundef{{( signext)?}} i8 @test_TwoZsts(i8 noundef{{( signext)?}} %_1)
 #[no_mangle]
 pub extern "C" fn test_TwoZsts(_: TwoZsts) -> TwoZsts { loop {} }
 
 #[repr(transparent)]
 pub struct Nested1(Zst2, Generic<f64>);
 
-// CHECK: define{{.*}}double @test_Nested1(double %_1)
+// CHECK: define{{.*}}double @test_Nested1(double noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_Nested1(_: Nested1) -> Nested1 { loop {} }
 
 #[repr(transparent)]
 pub struct Nested2(Nested1, Zst1);
 
-// CHECK: define{{.*}}double @test_Nested2(double %_1)
+// CHECK: define{{.*}}double @test_Nested2(double noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_Nested2(_: Nested2) -> Nested2 { loop {} }
 
@@ -115,7 +115,7 @@ pub extern "C" fn test_Vector(_: Vector) -> Vector { loop {} }
 #[repr(transparent)]
 pub struct StructWithProjection(<f32 as Mirror>::It);
 
-// CHECK: define{{.*}}float @test_Projection(float %_1)
+// CHECK: define{{.*}}float @test_Projection(float noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} }
 
@@ -124,7 +124,7 @@ pub enum EnumF32 {
     Variant(F32)
 }
 
-// CHECK: define{{.*}}float @test_EnumF32(float %_1)
+// CHECK: define{{.*}}float @test_EnumF32(float noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_EnumF32(_: EnumF32) -> EnumF32 { loop {} }
 
@@ -133,7 +133,7 @@ pub enum EnumF32WithZsts {
     Variant(Zst1, F32, Zst2)
 }
 
-// CHECK: define{{.*}}float @test_EnumF32WithZsts(float %_1)
+// CHECK: define{{.*}}float @test_EnumF32WithZsts(float noundef %_1)
 #[no_mangle]
 pub extern "C" fn test_EnumF32WithZsts(_: EnumF32WithZsts) -> EnumF32WithZsts { loop {} }
 
@@ -142,7 +142,7 @@ pub union UnionF32 {
     field: F32,
 }
 
-// CHECK: define{{.*}}float @test_UnionF32(float %_1)
+// CHECK: define{{.*}} float @test_UnionF32(float %_1)
 #[no_mangle]
 pub extern "C" fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} }
 
index 61c4b7b51af7be5344eb86985277d8605baa2820..045f01985a57f1e14a75a4085c382f2f3ff56c0f 100644 (file)
@@ -29,25 +29,25 @@ pub extern "C" fn f_scalar_0(a: bool) -> bool {
     a
 }
 
-// CHECK: define signext i8 @f_scalar_1(i8 signext %x)
+// CHECK: define noundef signext i8 @f_scalar_1(i8 noundef signext %x)
 #[no_mangle]
 pub extern "C" fn f_scalar_1(x: i8) -> i8 {
     x
 }
 
-// CHECK: define zeroext i8 @f_scalar_2(i8 zeroext %x)
+// CHECK: define noundef zeroext i8 @f_scalar_2(i8 noundef zeroext %x)
 #[no_mangle]
 pub extern "C" fn f_scalar_2(x: u8) -> u8 {
     x
 }
 
-// CHECK: define signext i32 @f_scalar_3(i32 signext %x)
+// CHECK: define noundef signext i32 @f_scalar_3(i32 noundef signext %x)
 #[no_mangle]
 pub extern "C" fn f_scalar_3(x: i32) -> u32 {
     x as u32
 }
 
-// CHECK: define i64 @f_scalar_4(i64 %x)
+// CHECK: define noundef i64 @f_scalar_4(i64 noundef %x)
 #[no_mangle]
 pub extern "C" fn f_scalar_4(x: i64) -> i64 {
     x
@@ -132,13 +132,13 @@ pub struct Large {
 pub extern "C" fn f_agg_large(mut x: Large) {
 }
 
-// CHECK: define void @f_agg_large_ret({{%Large\*|ptr}} {{.*}}sret{{.*}}, i32 signext %i, i8 signext %j)
+// CHECK: define void @f_agg_large_ret({{%Large\*|ptr}} {{.*}}sret{{.*}}, i32 noundef signext %i, i8 noundef signext %j)
 #[no_mangle]
 pub extern "C" fn f_agg_large_ret(i: i32, j: i8) -> Large {
     Large { a: 1, b: 2, c: 3, d: 4 }
 }
 
-// CHECK: define void @f_scalar_stack_1(i64 %0, [2 x i64] %1, i128 %2, {{%Large\*|ptr}} {{.*}}%d, i8 zeroext %e, i8 signext %f, i8 %g, i8 %h)
+// CHECK: define void @f_scalar_stack_1(i64 %0, [2 x i64] %1, i128 %2, {{%Large\*|ptr}} {{.*}}%d, i8 noundef zeroext %e, i8 noundef signext %f, i8 noundef %g, i8 noundef %h)
 #[no_mangle]
 pub extern "C" fn f_scalar_stack_1(
     a: Tiny,
@@ -152,7 +152,7 @@ pub extern "C" fn f_scalar_stack_1(
 ) {
 }
 
-// CHECK: define void @f_scalar_stack_2({{%Large\*|ptr}} {{.*}}sret{{.*}} %0, i64 %a, i128 %1, i128 %2, i64 %d, i8 zeroext %e, i8 %f, i8 %g)
+// CHECK: define void @f_scalar_stack_2({{%Large\*|ptr}} {{.*}}sret{{.*}} %0, i64 noundef %a, i128 %1, i128 %2, i64 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g)
 #[no_mangle]
 pub extern "C" fn f_scalar_stack_2(
     a: u64,
@@ -172,7 +172,7 @@ pub extern "C" fn f_scalar_stack_2(
 
 #[no_mangle]
 pub unsafe extern "C" fn f_va_caller() {
-    // CHECK: call signext i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i64 3, double {{.*}}, double {{.*}}, i64 {{.*}}, [2 x i64] {{.*}}, i128 {{.*}}, {{%Large\*|ptr}} {{.*}})
+    // CHECK: call noundef signext i32 (i32, ...) @f_va_callee(i32 noundef signext 1, i32 noundef signext 2, i64 noundef 3, double {{.*}}, double {{.*}}, i64 {{.*}}, [2 x i64] {{.*}}, i128 {{.*}}, {{%Large\*|ptr}} {{.*}})
     f_va_callee(
         1,
         2i32,
@@ -184,6 +184,6 @@ pub extern "C" fn f_scalar_stack_2(
         SmallAligned { a: 11 },
         Large { a: 12, b: 13, c: 14, d: 15 },
     );
-    // CHECK: call signext i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i128 {{.*}}, i32 signext 6, i32 signext 7, i32 8, i32 9)
+    // CHECK: call noundef signext i32 (i32, ...) @f_va_callee(i32 noundef signext 1, i32 noundef signext 2, i32 noundef signext 3, i32 noundef signext 4, i128 {{.*}}, i32 noundef signext 6, i32 noundef signext 7, i32 noundef 8, i32 noundef 9)
     f_va_callee(1, 2i32, 3i32, 4i32, SmallAligned { a: 5 }, 6i32, 7i32, 8i32, 9i32);
 }
index 8be5186de9e773781e950955272cefc85d29a2ce..597b867ebad143ade9660a48d6ed64ca08e0a8d9 100644 (file)
@@ -1,7 +1,7 @@
 // Verifies that pointer type membership tests for indirect calls are emitted.
 //
 // needs-sanitizer-cfi
-// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
+// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
 
 #![crate_type="lib"]
 
index 8e0d02550ee94a5fa859adb0edcd5c511c452965..2537df80a90b44b62f84d9e9aa037e0f9bc01e65 100644 (file)
@@ -5,7 +5,7 @@
 // [aarch64] needs-llvm-components: aarch64
 // [x86_64] compile-flags: --target x86_64-unknown-none
 // [x86_64] needs-llvm-components:
-// compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi
+// compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
 
 #![crate_type="lib"]
 #![feature(no_core, lang_items)]
index 7ce0fa0a20fc2ecad15669c069be8eedf0eadbdd..7b00fcf8e1bd743d6b7268b361626f0308574f60 100644 (file)
@@ -6,8 +6,8 @@
 // revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER MSAN-RECOVER-LTO
 // no-prefer-dynamic
 //
-//[ASAN]             compile-flags: -Zsanitizer=address
-//[ASAN-RECOVER]     compile-flags: -Zsanitizer=address -Zsanitizer-recover=address
+//[ASAN]             compile-flags: -Zsanitizer=address -Copt-level=0
+//[ASAN-RECOVER]     compile-flags: -Zsanitizer=address -Zsanitizer-recover=address -Copt-level=0
 //[MSAN]             compile-flags: -Zsanitizer=memory
 //[MSAN-RECOVER]     compile-flags: -Zsanitizer=memory  -Zsanitizer-recover=memory
 //[MSAN-RECOVER-LTO] compile-flags: -Zsanitizer=memory  -Zsanitizer-recover=memory -C lto=fat
 // ASAN-RECOVER-NOT:     unreachable
 // ASAN:               }
 //
-// MSAN-LABEL: define dso_local i32 @penguin(
+// MSAN-LABEL: define dso_local noundef i32 @penguin(
 // MSAN:         call void @__msan_warning{{(_with_origin_noreturn\(i32 0\)|_noreturn\(\))}}
 // MSAN:         unreachable
 // MSAN:       }
 //
-// MSAN-RECOVER-LABEL: define dso_local i32 @penguin(
+// MSAN-RECOVER-LABEL: define dso_local noundef i32 @penguin(
 // MSAN-RECOVER:         call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}}
 // MSAN-RECOVER-NOT:     unreachable
 // MSAN-RECOVER:       }
 //
-// MSAN-RECOVER-LTO-LABEL: define dso_local i32 @penguin(
+// MSAN-RECOVER-LTO-LABEL: define dso_local noundef i32 @penguin(
 // MSAN-RECOVER-LTO:          call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}}
 // MSAN-RECOVER-LTO-NOT:      unreachable
 // MSAN-RECOVER-LTO:       }
index 264f28fdb5feea5e115473b341f18a52eec08de5..8e8365b6a673b6baa8dea7a34d293bc8e420f167 100644 (file)
@@ -8,13 +8,13 @@ pub fn pair_bool_bool(pair: (bool, bool)) -> (bool, bool) {
     pair
 }
 
-// CHECK: define{{.*}}{ i8, i32 } @pair_bool_i32(i1 noundef zeroext %pair.0, i32 %pair.1)
+// CHECK: define{{.*}}{ i8, i32 } @pair_bool_i32(i1 noundef zeroext %pair.0, i32 noundef %pair.1)
 #[no_mangle]
 pub fn pair_bool_i32(pair: (bool, i32)) -> (bool, i32) {
     pair
 }
 
-// CHECK: define{{.*}}{ i32, i8 } @pair_i32_bool(i32 %pair.0, i1 noundef zeroext %pair.1)
+// CHECK: define{{.*}}{ i32, i8 } @pair_i32_bool(i32 noundef %pair.0, i1 noundef zeroext %pair.1)
 #[no_mangle]
 pub fn pair_i32_bool(pair: (i32, bool)) -> (i32, bool) {
     pair
index 7fc34af3da72a2d2137d3da41c9fd207737b4c91..9f2d9d06524f0d65a30dd56432a01216570aa34a 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Cno-prepopulate-passes
+// compile-flags: -Cno-prepopulate-passes -Copt-level=0
 
 // revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv
 
index b2afc7deb679aa40a23b4372ba4800f18d4afc2e..735ef7081c9566c057e9a9638b0c84d8e7731a81 100644 (file)
@@ -15,8 +15,8 @@
 // it to be marked `dso_local` as well, given the static relocation model.
 //
 // CHECK: @extern_static = external dso_local local_unnamed_addr global i8
-// CHECK: define dso_local i8 @access_extern() {{.*}}
-// CHECK: declare dso_local i8 @extern_fn() {{.*}}
+// CHECK: define dso_local noundef i8 @access_extern() {{.*}}
+// CHECK: declare dso_local noundef i8 @extern_fn() {{.*}}
 
 #[no_mangle]
 pub fn access_extern() -> u8 {
index a7e5deeffd8e24f16874a3dee1b9bbc62f4af637..260dcbac0fc4f33919ca7d43889f3b13d901ef07 100644 (file)
@@ -5,7 +5,7 @@
 // FIXME(eddyb) all of these tests show memory stores and loads, even after a
 // scalar `bitcast`, more special-casing is required to remove `alloca` usage.
 
-// CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float %x)
+// CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float noundef %x)
 // CHECK: store i32 %{{.*}}, {{.*}} %0
 // CHECK-NEXT: %[[RES:.*]] = load i32, {{.*}} %0
 // CHECK: ret i32 %[[RES]]
@@ -24,7 +24,7 @@ pub fn bool_to_byte(b: bool) -> u8 {
     unsafe { std::mem::transmute(b) }
 }
 
-// CHECK-LABEL: define{{.*}}noundef zeroext i1 @byte_to_bool(i8 %byte)
+// CHECK-LABEL: define{{.*}}noundef zeroext i1 @byte_to_bool(i8 noundef %byte)
 // CHECK: %1 = trunc i8 %byte to i1
 // CHECK-NEXT: %2 = zext i1 %1 to i8
 // CHECK-NEXT: store i8 %2, {{.*}} %0
@@ -36,7 +36,7 @@ pub unsafe fn byte_to_bool(byte: u8) -> bool {
     std::mem::transmute(byte)
 }
 
-// CHECK-LABEL: define{{.*}}{{i8\*|ptr}} @ptr_to_ptr({{i16\*|ptr}} %p)
+// CHECK-LABEL: define{{.*}}{{i8\*|ptr}} @ptr_to_ptr({{i16\*|ptr}} noundef %p)
 // CHECK: store {{i8\*|ptr}} %{{.*}}, {{.*}} %0
 // CHECK-NEXT: %[[RES:.*]] = load {{i8\*|ptr}}, {{.*}} %0
 // CHECK: ret {{i8\*|ptr}} %[[RES]]
@@ -52,7 +52,7 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
 // Tests below show the non-special-cased behavior (with the possible
 // future special-cased instructions in the "NOTE(eddyb)" comments).
 
-// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int({{i16\*|ptr}} %p)
+// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int({{i16\*|ptr}} noundef %p)
 
 // NOTE(eddyb) see above, the following two CHECK lines should ideally be this:
 //        %2 = ptrtoint i16* %p to [[USIZE]]
@@ -66,7 +66,7 @@ pub fn ptr_to_int(p: *mut u16) -> usize {
     unsafe { std::mem::transmute(p) }
 }
 
-// CHECK: define{{.*}}{{i16\*|ptr}} @int_to_ptr([[USIZE]] %i)
+// CHECK: define{{.*}}{{i16\*|ptr}} @int_to_ptr([[USIZE]] noundef %i)
 
 // NOTE(eddyb) see above, the following two CHECK lines should ideally be this:
 //        %2 = inttoptr [[USIZE]] %i to i16*
index e86c75f3f482607b204d715d879f4cfa5b136a40..35f760851451e108b124552924d048c32c7f23de 100644 (file)
@@ -1,5 +1,5 @@
 // ignore-emscripten
-// compile-flags: -C no-prepopulate-passes
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
 
 // Test that tuples get optimized layout, in particular with a ZST in the last field (#63244)
 
index 8f1b038708e667b9cfccd9b8ec4b7124aa314c3e..d4715efad73c0fe0855a3a22314dd662d735861d 100644 (file)
@@ -2,7 +2,7 @@
 
 #![crate_type = "lib"]
 
-// CHECK-LABEL: define{{.*}}i32 @test(i32 %a, i32 %b)
+// CHECK-LABEL: define{{.*}}i32 @test(i32 noundef %a, i32 noundef %b)
 #[no_mangle]
 pub fn test(a: u32, b: u32) -> u32 {
     let c = a + b;
index ae6e448f172f7fcd87bd6d67cb16ea00579199f1..4481a9d1e9983c0991c63f58bb6c23ecad1b3d00 100644 (file)
@@ -161,7 +161,24 @@ pub fn vec_option_bool(n: usize) -> Vec<Option<bool>> {
     vec![Some(false); n]
 }
 
+// CHECK-LABEL: @vec_option_i32
+#[no_mangle]
+pub fn vec_option_i32(n: usize) -> Vec<Option<i32>> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: ret void
+    vec![None; n]
+}
+
 // Ensure that __rust_alloc_zeroed gets the right attributes for LLVM to optimize it away.
-// CHECK: declare noalias ptr @__rust_alloc_zeroed(i64, i64 allocalign) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]]
+// CHECK: declare noalias noundef ptr @__rust_alloc_zeroed(i64 noundef, i64 allocalign noundef) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]]
 
 // CHECK-DAG: attributes [[RUST_ALLOC_ZEROED_ATTRS]] = { {{.*}} allockind("alloc,zeroed,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} }
index 844d5870a846fa6c52f362b3a2e578990c5cd4cc..cef4b9bdaaf0a2dc018ccd61cff0c3c0ab0d4f6c 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -C no-prepopulate-passes
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
 
 #![crate_type = "lib"]
 #![feature(repr_simd)]
index 0269015b46617521ce9deba5392e52f69d72b6d4..2898e75e0ee367696eac4cecf9533dfd6fd97643 100644 (file)
@@ -1,6 +1,7 @@
 // compile-flags:-g
 // min-gdb-version: 8.1
 // ignore-lldb
+// ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows
 
 // === CDB TESTS ==================================================================================
 
index c41c9ee21df892c2bde379b70a5c8386f3209a81..c122112e6c77a339dd4b17ac229899b523cbe1e7 100644 (file)
@@ -1,6 +1,7 @@
 // compile-flags:-g
 
 // min-gdb-version: 8.1
+// ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows
 
 // Tests the visualizations for `NonZero{I,U}{8,16,32,64,128,size}`, `Wrapping<T>` and
 // `Atomic{Bool,I8,I16,I32,I64,Isize,U8,U16,U32,U64,Usize}` located in `libcore.natvis`.
index 7d88e45caf2576cdedb2cce5115832d63844ac8e..de4099a7f50cb174f5cd8862b8bdd9cba7a02cee 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-windows
 // min-lldb-version: 310
 
 // compile-flags:-g
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/async_await.a-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir
new file mode 100644 (file)
index 0000000..2a7f90f
--- /dev/null
@@ -0,0 +1,41 @@
+// MIR for `a::{closure#0}` 0 generator_resume
+/* generator_layout = GeneratorLayout {
+    field_tys: {},
+    variant_fields: {
+        Unresumed(0): [],
+        Returned (1): [],
+        Panicked (2): [],
+    },
+    storage_conflicts: BitMatrix(0x0) {},
+} */
+
+fn a::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:11:14: 11:16]>, _2: &mut Context<'_>) -> Poll<()> {
+    debug _task_context => _4;           // in scope 0 at $DIR/async_await.rs:+0:14: +0:16
+    let mut _0: std::task::Poll<()>;     // return place in scope 0 at $DIR/async_await.rs:+0:14: +0:16
+    let mut _3: ();                      // in scope 0 at $DIR/async_await.rs:+0:14: +0:16
+    let mut _4: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+0:14: +0:16
+    let mut _5: u32;                     // in scope 0 at $DIR/async_await.rs:+0:14: +0:16
+
+    bb0: {
+        _5 = discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:11:14: 11:16]))); // scope 0 at $DIR/async_await.rs:+0:14: +0:16
+        switchInt(move _5) -> [0: bb1, 1: bb2, otherwise: bb3]; // scope 0 at $DIR/async_await.rs:+0:14: +0:16
+    }
+
+    bb1: {
+        _4 = move _2;                    // scope 0 at $DIR/async_await.rs:+0:14: +0:16
+        _3 = const ();                   // scope 0 at $DIR/async_await.rs:+0:14: +0:16
+        Deinit(_0);                      // scope 0 at $DIR/async_await.rs:+0:16: +0:16
+        ((_0 as Ready).0: ()) = move _3; // scope 0 at $DIR/async_await.rs:+0:16: +0:16
+        discriminant(_0) = 0;            // scope 0 at $DIR/async_await.rs:+0:16: +0:16
+        discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:11:14: 11:16]))) = 1; // scope 0 at $DIR/async_await.rs:+0:16: +0:16
+        return;                          // scope 0 at $DIR/async_await.rs:+0:16: +0:16
+    }
+
+    bb2: {
+        assert(const false, "`async fn` resumed after completion") -> bb2; // scope 0 at $DIR/async_await.rs:+0:14: +0:16
+    }
+
+    bb3: {
+        unreachable;                     // scope 0 at $DIR/async_await.rs:+0:14: +0:16
+    }
+}
diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
new file mode 100644 (file)
index 0000000..1449247
--- /dev/null
@@ -0,0 +1,351 @@
+// MIR for `b::{closure#0}` 0 generator_resume
+/* generator_layout = GeneratorLayout {
+    field_tys: {
+        _0: GeneratorSavedTy {
+            ty: impl std::future::Future<Output = ()>,
+            source_info: SourceInfo {
+                span: $DIR/async_await.rs:15:8: 15:14 (#9),
+                scope: scope[0],
+            },
+            ignore_for_traits: false,
+        },
+        _1: GeneratorSavedTy {
+            ty: impl std::future::Future<Output = ()>,
+            source_info: SourceInfo {
+                span: $DIR/async_await.rs:16:8: 16:14 (#12),
+                scope: scope[0],
+            },
+            ignore_for_traits: false,
+        },
+    },
+    variant_fields: {
+        Unresumed(0): [],
+        Returned (1): [],
+        Panicked (2): [],
+        Suspend0 (3): [_0],
+        Suspend1 (4): [_1],
+    },
+    storage_conflicts: BitMatrix(2x2) {
+        (_0, _0),
+        (_1, _1),
+    },
+} */
+
+fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>, _2: &mut Context<'_>) -> Poll<()> {
+    debug _task_context => _38;          // in scope 0 at $DIR/async_await.rs:+0:18: +3:2
+    let mut _0: std::task::Poll<()>;     // return place in scope 0 at $DIR/async_await.rs:+0:18: +3:2
+    let _3: ();                          // in scope 0 at $DIR/async_await.rs:+1:5: +1:14
+    let mut _4: impl std::future::Future<Output = ()>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14
+    let mut _5: impl std::future::Future<Output = ()>; // in scope 0 at $DIR/async_await.rs:+1:5: +1:8
+    let mut _6: impl std::future::Future<Output = ()>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14
+    let mut _7: ();                      // in scope 0 at $DIR/async_await.rs:+0:18: +3:2
+    let _8: ();                          // in scope 0 at $DIR/async_await.rs:+1:8: +1:14
+    let mut _9: std::task::Poll<()>;     // in scope 0 at $DIR/async_await.rs:+1:8: +1:14
+    let mut _10: std::pin::Pin<&mut impl std::future::Future<Output = ()>>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14
+    let mut _11: &mut impl std::future::Future<Output = ()>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14
+    let mut _12: &mut impl std::future::Future<Output = ()>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14
+    let mut _13: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+1:5: +1:14
+    let mut _14: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+1:5: +1:14
+    let mut _15: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14
+    let mut _16: isize;                  // in scope 0 at $DIR/async_await.rs:+1:8: +1:14
+    let mut _18: !;                      // in scope 0 at $DIR/async_await.rs:+1:5: +1:14
+    let mut _19: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14
+    let mut _20: ();                     // in scope 0 at $DIR/async_await.rs:+1:8: +1:14
+    let mut _21: impl std::future::Future<Output = ()>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14
+    let mut _22: impl std::future::Future<Output = ()>; // in scope 0 at $DIR/async_await.rs:+2:5: +2:8
+    let mut _23: impl std::future::Future<Output = ()>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14
+    let _24: ();                         // in scope 0 at $DIR/async_await.rs:+2:8: +2:14
+    let mut _25: std::task::Poll<()>;    // in scope 0 at $DIR/async_await.rs:+2:8: +2:14
+    let mut _26: std::pin::Pin<&mut impl std::future::Future<Output = ()>>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14
+    let mut _27: &mut impl std::future::Future<Output = ()>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14
+    let mut _28: &mut impl std::future::Future<Output = ()>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14
+    let mut _29: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+2:5: +2:14
+    let mut _30: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+2:5: +2:14
+    let mut _31: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14
+    let mut _32: isize;                  // in scope 0 at $DIR/async_await.rs:+2:8: +2:14
+    let mut _34: !;                      // in scope 0 at $DIR/async_await.rs:+2:5: +2:14
+    let mut _35: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14
+    let mut _36: ();                     // in scope 0 at $DIR/async_await.rs:+2:8: +2:14
+    let mut _37: ();                     // in scope 0 at $DIR/async_await.rs:+0:18: +3:2
+    let mut _38: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+0:18: +3:2
+    let mut _39: u32;                    // in scope 0 at $DIR/async_await.rs:+0:18: +3:2
+    scope 1 {
+        debug __awaitee => (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#3).0: impl std::future::Future<Output = ()>); // in scope 1 at $DIR/async_await.rs:+1:8: +1:14
+        let _17: ();                     // in scope 1 at $DIR/async_await.rs:+1:5: +1:14
+        scope 2 {
+        }
+        scope 3 {
+            debug result => _17;         // in scope 3 at $DIR/async_await.rs:+1:5: +1:14
+        }
+    }
+    scope 4 {
+        debug __awaitee => (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#4).0: impl std::future::Future<Output = ()>); // in scope 4 at $DIR/async_await.rs:+2:8: +2:14
+        let _33: ();                     // in scope 4 at $DIR/async_await.rs:+2:5: +2:14
+        scope 5 {
+        }
+        scope 6 {
+            debug result => _33;         // in scope 6 at $DIR/async_await.rs:+2:5: +2:14
+        }
+    }
+
+    bb0: {
+        _39 = discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2]))); // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+        switchInt(move _39) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb30]; // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+    }
+
+    bb1: {
+        _38 = move _2;                   // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+        StorageLive(_3);                 // scope 0 at $DIR/async_await.rs:+1:5: +1:14
+        StorageLive(_4);                 // scope 0 at $DIR/async_await.rs:+1:8: +1:14
+        StorageLive(_5);                 // scope 0 at $DIR/async_await.rs:+1:5: +1:8
+        _5 = a() -> bb2;                 // scope 0 at $DIR/async_await.rs:+1:5: +1:8
+                                         // mir::Constant
+                                         // + span: $DIR/async_await.rs:15:5: 15:6
+                                         // + literal: Const { ty: fn() -> impl Future<Output = ()> {a}, val: Value(<ZST>) }
+    }
+
+    bb2: {
+        _4 = <impl Future<Output = ()> as IntoFuture>::into_future(move _5) -> bb3; // scope 0 at $DIR/async_await.rs:+1:8: +1:14
+                                         // mir::Constant
+                                         // + span: $DIR/async_await.rs:15:8: 15:14
+                                         // + literal: Const { ty: fn(impl Future<Output = ()>) -> <impl Future<Output = ()> as IntoFuture>::IntoFuture {<impl Future<Output = ()> as IntoFuture>::into_future}, val: Value(<ZST>) }
+    }
+
+    bb3: {
+        StorageDead(_5);                 // scope 0 at $DIR/async_await.rs:+1:13: +1:14
+        nop;                             // scope 0 at $DIR/async_await.rs:+1:8: +1:14
+        (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#3).0: impl std::future::Future<Output = ()>) = move _4; // scope 0 at $DIR/async_await.rs:+1:8: +1:14
+        goto -> bb4;                     // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+    }
+
+    bb4: {
+        StorageLive(_8);                 // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+        StorageLive(_9);                 // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+        StorageLive(_10);                // scope 2 at $DIR/async_await.rs:+1:8: +1:14
+        StorageLive(_11);                // scope 2 at $DIR/async_await.rs:+1:8: +1:14
+        StorageLive(_12);                // scope 2 at $DIR/async_await.rs:+1:8: +1:14
+        _12 = &mut (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#3).0: impl std::future::Future<Output = ()>); // scope 2 at $DIR/async_await.rs:+1:8: +1:14
+        _11 = &mut (*_12);               // scope 2 at $DIR/async_await.rs:+1:8: +1:14
+        _10 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _11) -> bb5; // scope 2 at $DIR/async_await.rs:+1:8: +1:14
+                                         // mir::Constant
+                                         // + span: $DIR/async_await.rs:15:8: 15:14
+                                         // + literal: Const { ty: unsafe fn(&mut impl Future<Output = ()>) -> Pin<&mut impl Future<Output = ()>> {Pin::<&mut impl Future<Output = ()>>::new_unchecked}, val: Value(<ZST>) }
+    }
+
+    bb5: {
+        StorageDead(_11);                // scope 2 at $DIR/async_await.rs:+1:13: +1:14
+        StorageLive(_13);                // scope 2 at $DIR/async_await.rs:+1:5: +1:14
+        StorageLive(_14);                // scope 2 at $DIR/async_await.rs:+1:5: +1:14
+        StorageLive(_15);                // scope 2 at $DIR/async_await.rs:+1:8: +1:14
+        _15 = _38;                       // scope 2 at $DIR/async_await.rs:+1:8: +1:14
+        _14 = move _15;                  // scope 2 at $DIR/async_await.rs:+1:5: +1:14
+        goto -> bb6;                     // scope 2 at $DIR/async_await.rs:+1:5: +1:14
+    }
+
+    bb6: {
+        _13 = &mut (*_14);               // scope 2 at $DIR/async_await.rs:+1:5: +1:14
+        StorageDead(_15);                // scope 2 at $DIR/async_await.rs:+1:13: +1:14
+        _9 = <impl Future<Output = ()> as Future>::poll(move _10, move _13) -> bb7; // scope 2 at $DIR/async_await.rs:+1:8: +1:14
+                                         // mir::Constant
+                                         // + span: $DIR/async_await.rs:15:8: 15:14
+                                         // + literal: Const { ty: for<'a, 'b, 'c> fn(Pin<&'a mut impl Future<Output = ()>>, &'b mut Context<'c>) -> Poll<<impl Future<Output = ()> as Future>::Output> {<impl Future<Output = ()> as Future>::poll}, val: Value(<ZST>) }
+    }
+
+    bb7: {
+        StorageDead(_13);                // scope 2 at $DIR/async_await.rs:+1:13: +1:14
+        StorageDead(_10);                // scope 2 at $DIR/async_await.rs:+1:13: +1:14
+        _16 = discriminant(_9);          // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+        switchInt(move _16) -> [0: bb10, 1: bb8, otherwise: bb9]; // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+    }
+
+    bb8: {
+        _8 = const ();                   // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+        StorageDead(_14);                // scope 1 at $DIR/async_await.rs:+1:13: +1:14
+        StorageDead(_12);                // scope 1 at $DIR/async_await.rs:+1:13: +1:14
+        StorageDead(_9);                 // scope 1 at $DIR/async_await.rs:+1:13: +1:14
+        StorageDead(_8);                 // scope 1 at $DIR/async_await.rs:+1:13: +1:14
+        StorageLive(_19);                // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+        StorageLive(_20);                // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+        _20 = ();                        // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+        Deinit(_0);                      // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+        discriminant(_0) = 1;            // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+        discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2]))) = 3; // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+        return;                          // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+    }
+
+    bb9: {
+        unreachable;                     // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+    }
+
+    bb10: {
+        StorageLive(_17);                // scope 1 at $DIR/async_await.rs:+1:5: +1:14
+        _17 = ((_9 as Ready).0: ());     // scope 1 at $DIR/async_await.rs:+1:5: +1:14
+        _3 = _17;                        // scope 3 at $DIR/async_await.rs:+1:5: +1:14
+        StorageDead(_17);                // scope 1 at $DIR/async_await.rs:+1:13: +1:14
+        StorageDead(_14);                // scope 1 at $DIR/async_await.rs:+1:13: +1:14
+        StorageDead(_12);                // scope 1 at $DIR/async_await.rs:+1:13: +1:14
+        StorageDead(_9);                 // scope 1 at $DIR/async_await.rs:+1:13: +1:14
+        StorageDead(_8);                 // scope 1 at $DIR/async_await.rs:+1:13: +1:14
+        goto -> bb12;                    // scope 0 at $DIR/async_await.rs:+1:13: +1:14
+    }
+
+    bb11: {
+        StorageDead(_20);                // scope 1 at $DIR/async_await.rs:+1:13: +1:14
+        _38 = move _19;                  // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+        StorageDead(_19);                // scope 1 at $DIR/async_await.rs:+1:13: +1:14
+        _7 = const ();                   // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+        goto -> bb4;                     // scope 1 at $DIR/async_await.rs:+1:8: +1:14
+    }
+
+    bb12: {
+        nop;                             // scope 0 at $DIR/async_await.rs:+1:13: +1:14
+        goto -> bb13;                    // scope 0 at $DIR/async_await.rs:+1:14: +1:15
+    }
+
+    bb13: {
+        StorageDead(_4);                 // scope 0 at $DIR/async_await.rs:+1:14: +1:15
+        StorageDead(_3);                 // scope 0 at $DIR/async_await.rs:+1:14: +1:15
+        StorageLive(_21);                // scope 0 at $DIR/async_await.rs:+2:8: +2:14
+        StorageLive(_22);                // scope 0 at $DIR/async_await.rs:+2:5: +2:8
+        _22 = a() -> bb14;               // scope 0 at $DIR/async_await.rs:+2:5: +2:8
+                                         // mir::Constant
+                                         // + span: $DIR/async_await.rs:16:5: 16:6
+                                         // + literal: Const { ty: fn() -> impl Future<Output = ()> {a}, val: Value(<ZST>) }
+    }
+
+    bb14: {
+        _21 = <impl Future<Output = ()> as IntoFuture>::into_future(move _22) -> bb15; // scope 0 at $DIR/async_await.rs:+2:8: +2:14
+                                         // mir::Constant
+                                         // + span: $DIR/async_await.rs:16:8: 16:14
+                                         // + literal: Const { ty: fn(impl Future<Output = ()>) -> <impl Future<Output = ()> as IntoFuture>::IntoFuture {<impl Future<Output = ()> as IntoFuture>::into_future}, val: Value(<ZST>) }
+    }
+
+    bb15: {
+        StorageDead(_22);                // scope 0 at $DIR/async_await.rs:+2:13: +2:14
+        nop;                             // scope 0 at $DIR/async_await.rs:+2:8: +2:14
+        (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#4).0: impl std::future::Future<Output = ()>) = move _21; // scope 0 at $DIR/async_await.rs:+2:8: +2:14
+        goto -> bb16;                    // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+    }
+
+    bb16: {
+        StorageLive(_24);                // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+        StorageLive(_25);                // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+        StorageLive(_26);                // scope 5 at $DIR/async_await.rs:+2:8: +2:14
+        StorageLive(_27);                // scope 5 at $DIR/async_await.rs:+2:8: +2:14
+        StorageLive(_28);                // scope 5 at $DIR/async_await.rs:+2:8: +2:14
+        _28 = &mut (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#4).0: impl std::future::Future<Output = ()>); // scope 5 at $DIR/async_await.rs:+2:8: +2:14
+        _27 = &mut (*_28);               // scope 5 at $DIR/async_await.rs:+2:8: +2:14
+        _26 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _27) -> bb17; // scope 5 at $DIR/async_await.rs:+2:8: +2:14
+                                         // mir::Constant
+                                         // + span: $DIR/async_await.rs:16:8: 16:14
+                                         // + literal: Const { ty: unsafe fn(&mut impl Future<Output = ()>) -> Pin<&mut impl Future<Output = ()>> {Pin::<&mut impl Future<Output = ()>>::new_unchecked}, val: Value(<ZST>) }
+    }
+
+    bb17: {
+        StorageDead(_27);                // scope 5 at $DIR/async_await.rs:+2:13: +2:14
+        StorageLive(_29);                // scope 5 at $DIR/async_await.rs:+2:5: +2:14
+        StorageLive(_30);                // scope 5 at $DIR/async_await.rs:+2:5: +2:14
+        StorageLive(_31);                // scope 5 at $DIR/async_await.rs:+2:8: +2:14
+        _31 = _38;                       // scope 5 at $DIR/async_await.rs:+2:8: +2:14
+        _30 = move _31;                  // scope 5 at $DIR/async_await.rs:+2:5: +2:14
+        goto -> bb18;                    // scope 5 at $DIR/async_await.rs:+2:5: +2:14
+    }
+
+    bb18: {
+        _29 = &mut (*_30);               // scope 5 at $DIR/async_await.rs:+2:5: +2:14
+        StorageDead(_31);                // scope 5 at $DIR/async_await.rs:+2:13: +2:14
+        _25 = <impl Future<Output = ()> as Future>::poll(move _26, move _29) -> bb19; // scope 5 at $DIR/async_await.rs:+2:8: +2:14
+                                         // mir::Constant
+                                         // + span: $DIR/async_await.rs:16:8: 16:14
+                                         // + literal: Const { ty: for<'a, 'b, 'c> fn(Pin<&'a mut impl Future<Output = ()>>, &'b mut Context<'c>) -> Poll<<impl Future<Output = ()> as Future>::Output> {<impl Future<Output = ()> as Future>::poll}, val: Value(<ZST>) }
+    }
+
+    bb19: {
+        StorageDead(_29);                // scope 5 at $DIR/async_await.rs:+2:13: +2:14
+        StorageDead(_26);                // scope 5 at $DIR/async_await.rs:+2:13: +2:14
+        _32 = discriminant(_25);         // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+        switchInt(move _32) -> [0: bb22, 1: bb20, otherwise: bb21]; // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+    }
+
+    bb20: {
+        _24 = const ();                  // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+        StorageDead(_30);                // scope 4 at $DIR/async_await.rs:+2:13: +2:14
+        StorageDead(_28);                // scope 4 at $DIR/async_await.rs:+2:13: +2:14
+        StorageDead(_25);                // scope 4 at $DIR/async_await.rs:+2:13: +2:14
+        StorageDead(_24);                // scope 4 at $DIR/async_await.rs:+2:13: +2:14
+        StorageLive(_35);                // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+        StorageLive(_36);                // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+        _36 = ();                        // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+        Deinit(_0);                      // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+        discriminant(_0) = 1;            // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+        discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2]))) = 4; // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+        return;                          // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+    }
+
+    bb21: {
+        unreachable;                     // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+    }
+
+    bb22: {
+        StorageLive(_33);                // scope 4 at $DIR/async_await.rs:+2:5: +2:14
+        _33 = ((_25 as Ready).0: ());    // scope 4 at $DIR/async_await.rs:+2:5: +2:14
+        _37 = _33;                       // scope 6 at $DIR/async_await.rs:+2:5: +2:14
+        StorageDead(_33);                // scope 4 at $DIR/async_await.rs:+2:13: +2:14
+        StorageDead(_30);                // scope 4 at $DIR/async_await.rs:+2:13: +2:14
+        StorageDead(_28);                // scope 4 at $DIR/async_await.rs:+2:13: +2:14
+        StorageDead(_25);                // scope 4 at $DIR/async_await.rs:+2:13: +2:14
+        StorageDead(_24);                // scope 4 at $DIR/async_await.rs:+2:13: +2:14
+        goto -> bb24;                    // scope 0 at $DIR/async_await.rs:+2:13: +2:14
+    }
+
+    bb23: {
+        StorageDead(_36);                // scope 4 at $DIR/async_await.rs:+2:13: +2:14
+        _38 = move _35;                  // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+        StorageDead(_35);                // scope 4 at $DIR/async_await.rs:+2:13: +2:14
+        _7 = const ();                   // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+        goto -> bb16;                    // scope 4 at $DIR/async_await.rs:+2:8: +2:14
+    }
+
+    bb24: {
+        nop;                             // scope 0 at $DIR/async_await.rs:+2:13: +2:14
+        goto -> bb25;                    // scope 0 at $DIR/async_await.rs:+3:1: +3:2
+    }
+
+    bb25: {
+        StorageDead(_21);                // scope 0 at $DIR/async_await.rs:+3:1: +3:2
+        goto -> bb26;                    // scope 0 at $DIR/async_await.rs:+3:1: +3:2
+    }
+
+    bb26: {
+        Deinit(_0);                      // scope 0 at $DIR/async_await.rs:+3:2: +3:2
+        ((_0 as Ready).0: ()) = move _37; // scope 0 at $DIR/async_await.rs:+3:2: +3:2
+        discriminant(_0) = 0;            // scope 0 at $DIR/async_await.rs:+3:2: +3:2
+        discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2]))) = 1; // scope 0 at $DIR/async_await.rs:+3:2: +3:2
+        return;                          // scope 0 at $DIR/async_await.rs:+3:2: +3:2
+    }
+
+    bb27: {
+        StorageLive(_3);                 // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+        StorageLive(_4);                 // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+        StorageLive(_19);                // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+        StorageLive(_20);                // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+        _19 = move _2;                   // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+        goto -> bb11;                    // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+    }
+
+    bb28: {
+        StorageLive(_21);                // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+        StorageLive(_35);                // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+        StorageLive(_36);                // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+        _35 = move _2;                   // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+        goto -> bb23;                    // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+    }
+
+    bb29: {
+        assert(const false, "`async fn` resumed after completion") -> bb29; // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+    }
+
+    bb30: {
+        unreachable;                     // scope 0 at $DIR/async_await.rs:+0:18: +3:2
+    }
+}
diff --git a/tests/mir-opt/building/async_await.rs b/tests/mir-opt/building/async_await.rs
new file mode 100644 (file)
index 0000000..0b991e3
--- /dev/null
@@ -0,0 +1,17 @@
+// This test makes sure that the generator MIR pass eliminates all calls to
+// `get_context`, and that the MIR argument type for an async fn and all locals
+// related to `yield` are `&mut Context`, and its return type is `Poll`.
+
+// edition:2018
+// compile-flags: -C panic=abort
+
+#![crate_type = "lib"]
+
+// EMIT_MIR async_await.a-{closure#0}.generator_resume.0.mir
+async fn a() {}
+
+// EMIT_MIR async_await.b-{closure#0}.generator_resume.0.mir
+pub async fn b() {
+    a().await;
+    a().await
+}
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 ff4fe1a93246ec0406679043402502f1e7d6a9f2..16d10eb5968c1b897b178a2fa30cd0526e370b8c 100644 (file)
@@ -18,8 +18,8 @@ fn consts<const C: u32>() {
     })
 }
 
-static S: i32 = 5;
-static mut T: i32 = 10;
+static S: i32 = 0x05050505;
+static mut T: i32 = 0x0a0a0a0a;
 // EMIT_MIR consts.statics.built.after.mir
 #[custom_mir(dialect = "built")]
 fn statics() {
index ee768e263ecdf9d536a824f6600cd04194461847..bfef976aa02726b299276088ac0e5e343b97b3b3 100644 (file)
@@ -19,9 +19,9 @@ fn statics() -> () {
 }
 
 alloc2 (static: T, size: 4, align: 4) {
-    0a 00 00 00                                     │ ....
+    0a 0a 0a 0a                                     │ ....
 }
 
 alloc1 (static: S, size: 4, align: 4) {
-    05 00 00 00                                     │ ....
+    05 05 05 05                                     │ ....
 }
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()
+    })
+}
index ec6dbe1d0526b7799436afe1729994cb59411936..db041aab239e38e53845fec8cc3f293577a325ae 100644 (file)
@@ -11,12 +11,14 @@ pub fn simple(x: i32) -> i32 {
         let temp2: _;
 
         {
+            StorageLive(temp1);
             temp1 = x;
             Goto(exit)
         }
 
         exit = {
             temp2 = Move(temp1);
+            StorageDead(temp1);
             RET = temp2;
             Return()
         }
index d7560fde69c9500412035d2815c5995e57d659d0..743016708c583ae8cac3f1655dd6c8a2a02f05c7 100644 (file)
@@ -6,13 +6,15 @@ fn simple(_1: i32) -> i32 {
     let mut _3: i32;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
 
     bb0: {
-        _2 = _1;                         // scope 0 at $DIR/simple_assign.rs:+6:13: +6:22
-        goto -> bb1;                     // scope 0 at $DIR/simple_assign.rs:+7:13: +7:23
+        StorageLive(_2);                 // scope 0 at $DIR/simple_assign.rs:+6:13: +6:31
+        _2 = _1;                         // scope 0 at $DIR/simple_assign.rs:+7:13: +7:22
+        goto -> bb1;                     // scope 0 at $DIR/simple_assign.rs:+8:13: +8:23
     }
 
     bb1: {
-        _3 = move _2;                    // scope 0 at $DIR/simple_assign.rs:+11:13: +11:32
-        _0 = _3;                         // scope 0 at $DIR/simple_assign.rs:+12:13: +12:24
-        return;                          // scope 0 at $DIR/simple_assign.rs:+13:13: +13:21
+        _3 = move _2;                    // scope 0 at $DIR/simple_assign.rs:+12:13: +12:32
+        StorageDead(_2);                 // scope 0 at $DIR/simple_assign.rs:+13:13: +13:31
+        _0 = _3;                         // scope 0 at $DIR/simple_assign.rs:+14:13: +14:24
+        return;                          // scope 0 at $DIR/simple_assign.rs:+15:13: +15:21
     }
 }
index dd548adde7e5fe0f05f5ddd7b8d6c642e92d7762..5e587be1f1653f482d6bb3a8678ce14bf847cfda 100644 (file)
           _3 = const 3_u8;                 // scope 2 at $DIR/const_debuginfo.rs:+3:13: +3:16
           StorageLive(_4);                 // scope 3 at $DIR/const_debuginfo.rs:+4:9: +4:12
           StorageLive(_5);                 // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:20
-          StorageLive(_6);                 // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:16
-          _6 = const 1_u8;                 // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:16
-          StorageLive(_7);                 // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20
-          _7 = const 2_u8;                 // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20
           _5 = const 3_u8;                 // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:20
-          StorageDead(_7);                 // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20
-          StorageDead(_6);                 // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20
-          StorageLive(_8);                 // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24
-          _8 = const 3_u8;                 // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24
           _4 = const 6_u8;                 // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:24
-          StorageDead(_8);                 // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24
           StorageDead(_5);                 // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24
           StorageLive(_9);                 // scope 4 at $DIR/const_debuginfo.rs:+6:9: +6:10
           _9 = const "hello, world!";      // scope 4 at $DIR/const_debuginfo.rs:+6:13: +6:28
           StorageDead(_16);                // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
           StorageDead(_9);                 // scope 4 at $DIR/const_debuginfo.rs:+14:1: +14:2
           StorageDead(_4);                 // scope 3 at $DIR/const_debuginfo.rs:+14:1: +14:2
-          StorageDead(_3);                 // scope 2 at $DIR/const_debuginfo.rs:+14:1: +14:2
-          StorageDead(_2);                 // scope 1 at $DIR/const_debuginfo.rs:+14:1: +14:2
-          StorageDead(_1);                 // scope 0 at $DIR/const_debuginfo.rs:+14:1: +14:2
           return;                          // scope 0 at $DIR/const_debuginfo.rs:+14:2: +14:2
       }
   }
index 8485703e39f2c5b1b68261bf650caf15ef2f49c8..e085a88b2da8ba155f44730090f1545df43ce64b 100644 (file)
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:9: +1:10
           _1 = const 0_i32;                // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:13: +1:14
           StorageLive(_2);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:9: +2:11
-          StorageLive(_3);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
--         _3 = _1;                         // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
--         _4 = Eq(_3, const 0_i32);        // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+-         _4 = Eq(_1, const 0_i32);        // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 -         assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+         _3 = const 0_i32;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
 +         _4 = const true;                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
       }
   
       bb1: {
--         _5 = Eq(_3, const -1_i32);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+          _5 = Eq(_1, const -1_i32);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 -         _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 -         _7 = BitAnd(move _5, move _6);   // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
--         assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+         _5 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+-         assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _1) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         _6 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         _7 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+         assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
++         assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _1) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
       }
   
       bb2: {
--         _2 = Rem(const 1_i32, move _3);  // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+         _2 = Rem(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-          StorageDead(_3);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
+          _2 = Rem(const 1_i32, _1);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
           StorageDead(_2);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
-          StorageDead(_1);                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:2: +3:2
       }
   }
index 27e41d4869d759b74f8cad5bbc981311a0b7cb26..4bd0aa09872398959e3fbe0a1ea2c12050020756 100644 (file)
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          StorageLive(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _8 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
                                            // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
-          _3 = _8;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _2 = &raw const (*_8);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           StorageDead(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
-          StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
           StorageLive(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
           StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
           _5 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
index 27e41d4869d759b74f8cad5bbc981311a0b7cb26..4bd0aa09872398959e3fbe0a1ea2c12050020756 100644 (file)
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          StorageLive(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _8 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
                                            // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
-          _3 = _8;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _2 = &raw const (*_8);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           StorageDead(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
-          StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
           StorageLive(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
           StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
           _5 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
index 0de800917534a4492ffc9c886036880d1dd99659..549b4711e874d281f62050ad68226ced07af3c9f 100644 (file)
   
       bb0: {
           StorageLive(_3);                 // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15
-          StorageLive(_4);                 // scope 0 at $DIR/boolean_identities.rs:+1:6: +1:7
-          _4 = _2;                         // scope 0 at $DIR/boolean_identities.rs:+1:6: +1:7
--         _3 = BitOr(move _4, const true); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15
+-         _3 = BitOr(_2, const true);      // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15
 +         _3 = const true;                 // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15
-          StorageDead(_4);                 // scope 0 at $DIR/boolean_identities.rs:+1:14: +1:15
           StorageLive(_5);                 // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
-          StorageLive(_6);                 // scope 0 at $DIR/boolean_identities.rs:+1:19: +1:20
-          _6 = _1;                         // scope 0 at $DIR/boolean_identities.rs:+1:19: +1:20
--         _5 = BitAnd(move _6, const false); // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
-+         _5 = const false;                // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
-          StorageDead(_6);                 // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29
+-         _5 = BitAnd(_1, const false);    // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
 -         _0 = BitAnd(move _3, move _5);   // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:29
++         _5 = const false;                // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
 +         _0 = const false;                // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:29
           StorageDead(_5);                 // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29
           StorageDead(_3);                 // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29
index 629c8e60148fdbd8fdf465cedaa593b51e1643b3..1cfe47d0a86124a119b2ecd87221cbc9d2a4f38e 100644 (file)
@@ -7,11 +7,8 @@
       let mut _2: i32;                     // in scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4
-          _2 = _1;                         // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4
--         _0 = Mul(move _2, const 0_i32);  // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8
+-         _0 = Mul(_1, const 0_i32);       // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8
 +         _0 = const 0_i32;                // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8
-          StorageDead(_2);                 // scope 0 at $DIR/mult_by_zero.rs:+1:7: +1:8
           return;                          // scope 0 at $DIR/mult_by_zero.rs:+2:2: +2:2
       }
   }
index b9d551c5e5fc26a318b368d671927eb65ac77146..7fa29cccd50d602b0e01bc4ed258c20cadc8564a 100644 (file)
@@ -38,6 +38,6 @@
   }
   
   alloc1 (static: STATIC, size: 4, align: 4) {
-      2a 00 00 00                                     │ *...
+      42 42 42 42                                     │ BBBB
   }
   
index 8c23c5fcf0f88948a0952e751394e693bd26ca30..b69ec931a6311360a097698f26319e9e7b57a899 100644 (file)
@@ -1,7 +1,7 @@
 // unit-test
 // compile-flags: -O
 
-static mut STATIC: u32 = 42;
+static mut STATIC: u32 = 0x42424242;
 
 // EMIT_MIR mutable_variable_no_prop.main.ConstProp.diff
 fn main() {
index 8a73f0390e122fab4b66423fe548ef3ac0759051..924a267f3d8ffe5089f03bb6940d144a50d4defb 100644 (file)
           StorageLive(_2);                 // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
           _4 = const _;                    // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
                                            // mir::Constant
-                                           // + span: $DIR/ref_deref.rs:6:6: 6:10
+                                           // + span: $DIR/ref_deref.rs:5:6: 5:10
                                            // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
-          _2 = _4;                         // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
--         _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
-+         _1 = const 4_i32;                // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
+          _2 = &(*_4);                     // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
+          _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
           StorageDead(_2);                 // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
           StorageDead(_1);                 // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
-          nop;                             // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/ref_deref.rs:+2:2: +2:2
       }
   }
diff --git a/tests/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/tests/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff
deleted file mode 100644 (file)
index 015ec4d..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-- // MIR for `main` before PromoteTemps
-+ // MIR for `main` after PromoteTemps
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/ref_deref.rs:+0:11: +0:11
-      let _1: i32;                         // in scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
-      let mut _2: &i32;                    // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-      let _3: i32;                         // in scope 0 at $DIR/ref_deref.rs:+1:8: +1:9
-+     let mut _4: &i32;                    // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
-          StorageLive(_2);                 // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
--         StorageLive(_3);                 // scope 0 at $DIR/ref_deref.rs:+1:8: +1:9
--         _3 = const 4_i32;                // scope 0 at $DIR/ref_deref.rs:+1:8: +1:9
--         _2 = &_3;                        // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-+         _4 = const _;                    // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-+                                          // mir::Constant
-+                                          // + span: $DIR/ref_deref.rs:6:6: 6:10
-+                                          // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
-+         _2 = &(*_4);                     // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-          _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
--         StorageDead(_3);                 // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
-          StorageDead(_2);                 // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
-          StorageDead(_1);                 // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
-          _0 = const ();                   // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2
-          return;                          // scope 0 at $DIR/ref_deref.rs:+2:2: +2:2
-      }
-  }
-  
index d2549c8b6aa5aa13277bcc168dc6edb04f277264..76e56916af09aa32606552cdfc5b83c92c81f84f 100644 (file)
@@ -1,5 +1,4 @@
-// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
-// EMIT_MIR ref_deref.main.PromoteTemps.diff
+// unit-test: ConstProp
 // EMIT_MIR ref_deref.main.ConstProp.diff
 
 fn main() {
index ec3d90433159db1b596990220f44be4458e051cb..59095b4483713cc3fd806fadb83baae288c0b3a6 100644 (file)
           StorageLive(_2);                 // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
           _4 = const _;                    // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
                                            // mir::Constant
-                                           // + span: $DIR/ref_deref_project.rs:6:6: 6:17
+                                           // + span: $DIR/ref_deref_project.rs:5:6: 5:17
                                            // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) }
           _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
           StorageDead(_2);                 // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
           StorageDead(_1);                 // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
-          nop;                             // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/ref_deref_project.rs:+2:2: +2:2
       }
   }
diff --git a/tests/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/tests/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
deleted file mode 100644 (file)
index cd0616e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-- // MIR for `main` before PromoteTemps
-+ // MIR for `main` after PromoteTemps
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/ref_deref_project.rs:+0:11: +0:11
-      let _1: i32;                         // in scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
-      let mut _2: &i32;                    // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-      let _3: (i32, i32);                  // in scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14
-+     let mut _4: &(i32, i32);             // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
-          StorageLive(_2);                 // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
--         StorageLive(_3);                 // scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14
--         _3 = (const 4_i32, const 5_i32); // scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14
--         _2 = &(_3.1: i32);               // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-+         _4 = const _;                    // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-+                                          // mir::Constant
-+                                          // + span: $DIR/ref_deref_project.rs:6:6: 6:17
-+                                          // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) }
-+         _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-          _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
--         StorageDead(_3);                 // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
-          StorageDead(_2);                 // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
-          StorageDead(_1);                 // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
-          _0 = const ();                   // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2
-          return;                          // scope 0 at $DIR/ref_deref_project.rs:+2:2: +2:2
-      }
-  }
-  
index 2fdd4e15319014cd28efabf768483b81bcd84044..04fc7f8daa1240b9eb5ca2bc02797ca1154fcbaf 100644 (file)
@@ -1,5 +1,4 @@
-// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
-// EMIT_MIR ref_deref_project.main.PromoteTemps.diff
+// unit-test: ConstProp
 // EMIT_MIR ref_deref_project.main.ConstProp.diff
 
 fn main() {
index d518eff04eba21af52d1036f9ba2c6a2f808b444..e3f5b120a3234d8bb12f2eb2b99fe3199f04422d 100644 (file)
           StorageLive(_1);                 // scope 0 at $DIR/scalar_literal_propagation.rs:+1:9: +1:10
           _1 = const 1_u32;                // scope 0 at $DIR/scalar_literal_propagation.rs:+1:13: +1:14
           StorageLive(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
-          StorageLive(_3);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
--         _3 = _1;                         // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
--         _2 = consume(move _3) -> bb1;    // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
-+         _3 = const 1_u32;                // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
+-         _2 = consume(_1) -> bb1;         // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
 +         _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
                                            // mir::Constant
                                            // + span: $DIR/scalar_literal_propagation.rs:4:5: 4:12
@@ -25,9 +22,7 @@
       }
   
       bb1: {
-          StorageDead(_3);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:14: +2:15
           StorageDead(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16
-          StorageDead(_1);                 // scope 0 at $DIR/scalar_literal_propagation.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2
       }
   }
index 9017fd18e48752f510e3326a1fbcfdcc1d49f6c9..b99b83b0cba8540144dc76fd70b47477e79fa405 100644 (file)
@@ -20,7 +20,7 @@
           StorageLive(_4);                 // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _9 = const _;                    // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
                                            // mir::Constant
-                                           // + span: $DIR/slice_len.rs:6:6: 6:19
+                                           // + span: $DIR/slice_len.rs:7:6: 7:19
                                            // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
@@ -33,7 +33,7 @@
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 +         _7 = const 3_usize;              // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 +         _8 = const true;                 // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
       }
   
       bb1: {
@@ -43,7 +43,7 @@
           StorageDead(_4);                 // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
           StorageDead(_2);                 // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
           StorageDead(_1);                 // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
-          nop;                             // scope 0 at $DIR/slice_len.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/slice_len.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/slice_len.rs:+2:2: +2:2
       }
   }
index 9017fd18e48752f510e3326a1fbcfdcc1d49f6c9..b99b83b0cba8540144dc76fd70b47477e79fa405 100644 (file)
@@ -20,7 +20,7 @@
           StorageLive(_4);                 // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _9 = const _;                    // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
                                            // mir::Constant
-                                           // + span: $DIR/slice_len.rs:6:6: 6:19
+                                           // + span: $DIR/slice_len.rs:7:6: 7:19
                                            // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
@@ -33,7 +33,7 @@
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 +         _7 = const 3_usize;              // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
 +         _8 = const true;                 // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
       }
   
       bb1: {
@@ -43,7 +43,7 @@
           StorageDead(_4);                 // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
           StorageDead(_2);                 // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
           StorageDead(_1);                 // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
-          nop;                             // scope 0 at $DIR/slice_len.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/slice_len.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/slice_len.rs:+2:2: +2:2
       }
   }
index eaaf34b960eb66a84bd0ef5f43aa95c3b26e3bcc..8183def0c63dbda29ffd08a43dd70fa1fb8cfcfb 100644 (file)
@@ -1,4 +1,5 @@
-// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
+// unit-test: ConstProp
+// compile-flags: -Zmir-enable-passes=+InstCombine
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 // EMIT_MIR slice_len.main.ConstProp.diff
index ea9fec0aa15d1a6f0c09371fbbe1ecacb9bc2a98..b6b542fb79436d3ce1b3b8dacdb4202e57e0aa01 100644 (file)
@@ -4,15 +4,16 @@
   fn bar() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +0:10
       let mut _1: (i32,);                  // in scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
-      let mut _2: *mut i32;                // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
-      let mut _4: i32;                     // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
+      let _2: ();                          // in scope 0 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
+      let mut _3: *mut i32;                // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+      let mut _5: i32;                     // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
       scope 1 {
           debug v => _1;                   // in scope 1 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
-          let _3: bool;                    // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+          let _4: bool;                    // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
           scope 2 {
           }
           scope 3 {
-              debug y => _3;               // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+              debug y => _4;               // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
           }
       }
   
           StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
           Deinit(_1);                      // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
           (_1.0: i32) = const 1_i32;       // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
-          StorageLive(_2);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
-          _2 = &raw mut (_1.0: i32);       // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
-          (*_2) = const 5_i32;             // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26
-          StorageDead(_2);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27
-          StorageLive(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
-          StorageLive(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
-          _4 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18
-          _3 = Eq(move _4, const 5_i32);   // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25
-          StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25
-          StorageDead(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
+          StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
+          StorageLive(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+          _3 = &raw mut (_1.0: i32);       // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+          (*_3) = const 5_i32;             // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26
+          StorageDead(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27
+          _2 = const ();                   // scope 2 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
+          StorageDead(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:+4:5: +4:6
+          StorageLive(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+          StorageLive(_5);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
+          _5 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18
+          _4 = Eq(move _5, const 5_i32);   // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25
+          StorageDead(_5);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25
+          _0 = const ();                   // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +6:2
+          StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
           StorageDead(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
           return;                          // scope 0 at $DIR/const_prop_miscompile.rs:+6:2: +6:2
       }
index 043f404741710a9af58bb2d0f7d7781e350659f9..e43735fd9e145057c6ea8395c378fc5aeb5e2657 100644 (file)
@@ -27,6 +27,7 @@
           _4 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:+3:15: +3:18
           _3 = Eq(move _4, const 5_i32);   // scope 1 at $DIR/const_prop_miscompile.rs:+3:13: +3:25
           StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+3:24: +3:25
+          _0 = const ();                   // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +4:2
           StorageDead(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:+4:1: +4:2
           StorageDead(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/const_prop_miscompile.rs:+4:2: +4:2
index bc54556b34947293028575a8a033d3153924cc3b..dbbe5ee08408f4b9c7d4ea1a783bf4cac5566da6 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 #![feature(raw_ref_op)]
 
 // EMIT_MIR const_prop_miscompile.foo.ConstProp.diff
diff --git a/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff b/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff
new file mode 100644 (file)
index 0000000..b183865
--- /dev/null
@@ -0,0 +1,34 @@
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+  
+  fn f() -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/borrowed_local.rs:+0:11: +0:15
+      let mut _1: u8;                      // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+      let mut _2: &u8;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+      let mut _3: u8;                      // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+      let mut _4: &u8;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+  
+      bb0: {
+          _1 = const 5_u8;                 // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          _2 = &_1;                        // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          _3 = _1;                         // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          _4 = &_3;                        // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          _0 = cmp_ref(_2, _4) -> bb1;     // scope 0 at $DIR/borrowed_local.rs:+8:13: +8:45
+                                           // mir::Constant
+                                           // + span: $DIR/borrowed_local.rs:23:29: 23:36
+                                           // + literal: Const { ty: for<'a, 'b> fn(&'a u8, &'b u8) -> bool {cmp_ref}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+-         _0 = opaque::<u8>(_3) -> bb2;    // scope 0 at $DIR/borrowed_local.rs:+12:13: +12:38
++         _0 = opaque::<u8>(_1) -> bb2;    // scope 0 at $DIR/borrowed_local.rs:+12:13: +12:38
+                                           // mir::Constant
+                                           // + span: $DIR/borrowed_local.rs:27:28: 27:34
+                                           // + literal: Const { ty: fn(u8) -> bool {opaque::<u8>}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          return;                          // scope 0 at $DIR/borrowed_local.rs:+15:13: +15:21
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/borrowed_local.rs b/tests/mir-opt/copy-prop/borrowed_local.rs
new file mode 100644 (file)
index 0000000..c4b980e
--- /dev/null
@@ -0,0 +1,39 @@
+// unit-test: CopyProp
+
+#![feature(custom_mir, core_intrinsics)]
+#![allow(unused_assignments)]
+extern crate core;
+use core::intrinsics::mir::*;
+
+fn opaque(_: impl Sized) -> bool { true }
+
+fn cmp_ref(a: &u8, b: &u8) -> bool {
+    std::ptr::eq(a as *const u8, b as *const u8)
+}
+
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn f() -> bool {
+    mir!(
+        {
+            let a = 5_u8;
+            let r1 = &a;
+            let b = a;
+            // We cannot propagate the place `a`.
+            let r2 = &b;
+            Call(RET, next, cmp_ref(r1, r2))
+        }
+        next = {
+            // But we can propagate the value `a`.
+            Call(RET, ret, opaque(b))
+        }
+        ret = {
+            Return()
+        }
+    )
+}
+
+fn main() {
+    assert!(!f());
+}
+
+// EMIT_MIR borrowed_local.f.CopyProp.diff
diff --git a/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff b/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff
new file mode 100644 (file)
index 0000000..8b11653
--- /dev/null
@@ -0,0 +1,65 @@
+- // MIR for `foo` before CopyProp
++ // MIR for `foo` after CopyProp
+  
+  fn foo() -> i32 {
+      let mut _0: i32;                     // return place in scope 0 at $DIR/branch.rs:+0:13: +0:16
+      let _1: i32;                         // in scope 0 at $DIR/branch.rs:+1:9: +1:10
+      let mut _3: bool;                    // in scope 0 at $DIR/branch.rs:+3:16: +3:22
+      let _4: i32;                         // in scope 0 at $DIR/branch.rs:+6:9: +6:14
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/branch.rs:+1:9: +1:10
+          let _2: i32;                     // in scope 1 at $DIR/branch.rs:+3:9: +3:10
+          scope 2 {
+              debug y => _2;               // in scope 2 at $DIR/branch.rs:+3:9: +3:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/branch.rs:+1:9: +1:10
+          _1 = val() -> bb1;               // scope 0 at $DIR/branch.rs:+1:13: +1:18
+                                           // mir::Constant
+                                           // + span: $DIR/branch.rs:13:13: 13:16
+                                           // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageLive(_2);                 // scope 1 at $DIR/branch.rs:+3:9: +3:10
+          StorageLive(_3);                 // scope 1 at $DIR/branch.rs:+3:16: +3:22
+          _3 = cond() -> bb2;              // scope 1 at $DIR/branch.rs:+3:16: +3:22
+                                           // mir::Constant
+                                           // + span: $DIR/branch.rs:15:16: 15:20
+                                           // + literal: Const { ty: fn() -> bool {cond}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          switchInt(move _3) -> [0: bb4, otherwise: bb3]; // scope 1 at $DIR/branch.rs:+3:16: +3:22
+      }
+  
+      bb3: {
+          _2 = _1;                         // scope 1 at $DIR/branch.rs:+4:9: +4:10
+          goto -> bb6;                     // scope 1 at $DIR/branch.rs:+3:13: +8:6
+      }
+  
+      bb4: {
+          StorageLive(_4);                 // scope 1 at $DIR/branch.rs:+6:9: +6:14
+          _4 = val() -> bb5;               // scope 1 at $DIR/branch.rs:+6:9: +6:14
+                                           // mir::Constant
+                                           // + span: $DIR/branch.rs:18:9: 18:12
+                                           // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) }
+      }
+  
+      bb5: {
+          StorageDead(_4);                 // scope 1 at $DIR/branch.rs:+6:14: +6:15
+          _2 = _1;                         // scope 1 at $DIR/branch.rs:+7:9: +7:10
+          goto -> bb6;                     // scope 1 at $DIR/branch.rs:+3:13: +8:6
+      }
+  
+      bb6: {
+          StorageDead(_3);                 // scope 1 at $DIR/branch.rs:+8:5: +8:6
+          _0 = _2;                         // scope 2 at $DIR/branch.rs:+10:5: +10:6
+          StorageDead(_2);                 // scope 1 at $DIR/branch.rs:+11:1: +11:2
+          StorageDead(_1);                 // scope 0 at $DIR/branch.rs:+11:1: +11:2
+          return;                          // scope 0 at $DIR/branch.rs:+11:2: +11:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/branch.rs b/tests/mir-opt/copy-prop/branch.rs
new file mode 100644 (file)
index 0000000..50b1e00
--- /dev/null
@@ -0,0 +1,27 @@
+//! Tests that we bail out when there are multiple assignments to the same local.
+// unit-test: CopyProp
+fn val() -> i32 {
+    1
+}
+
+fn cond() -> bool {
+    true
+}
+
+// EMIT_MIR branch.foo.CopyProp.diff
+fn foo() -> i32 {
+    let x = val();
+
+    let y = if cond() {
+        x
+    } else {
+        val();
+        x
+    };
+
+    y
+}
+
+fn main() {
+    foo();
+}
diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff
new file mode 100644 (file)
index 0000000..69acebf
--- /dev/null
@@ -0,0 +1,21 @@
+- // MIR for `arg_src` before CopyProp
++ // MIR for `arg_src` after CopyProp
+  
+  fn arg_src(_1: i32) -> i32 {
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:+0:12: +0:17
+      let mut _0: i32;                     // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:27: +0:30
+      let _2: i32;                         // in scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10
+      scope 1 {
+          debug y => _2;                   // in scope 1 at $DIR/copy_propagation_arg.rs:+1:9: +1:10
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10
+          _2 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14
+          _1 = const 123_i32;              // scope 1 at $DIR/copy_propagation_arg.rs:+2:5: +2:12
+          _0 = _2;                         // scope 1 at $DIR/copy_propagation_arg.rs:+3:5: +3:6
+          StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+4:1: +4:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff
new file mode 100644 (file)
index 0000000..ac4e9a2
--- /dev/null
@@ -0,0 +1,28 @@
+- // MIR for `bar` before CopyProp
++ // MIR for `bar` after CopyProp
+  
+  fn bar(_1: u8) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13
+      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +0:19
+      let _2: u8;                          // in scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13
+      let mut _3: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13
+          StorageLive(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12
+          _3 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12
+          _2 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13
+                                           // mir::Constant
+                                           // + span: $DIR/copy_propagation_arg.rs:16:5: 16:10
+                                           // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageDead(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:+1:12: +1:13
+          StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14
+          _1 = const 5_u8;                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:10
+          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +3:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:+3:2: +3:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.baz.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.baz.CopyProp.diff
new file mode 100644 (file)
index 0000000..7ab6ebb
--- /dev/null
@@ -0,0 +1,18 @@
+- // MIR for `baz` before CopyProp
++ // MIR for `baz` after CopyProp
+  
+  fn baz(_1: i32) -> i32 {
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13
+      let mut _0: i32;                     // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:23: +0:26
+      let mut _2: i32;                     // in scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10
+          _2 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10
+          _1 = move _2;                    // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:10
+          StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10
+          _0 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:+3:5: +3:6
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff
new file mode 100644 (file)
index 0000000..0a3e985
--- /dev/null
@@ -0,0 +1,28 @@
+- // MIR for `foo` before CopyProp
++ // MIR for `foo` after CopyProp
+  
+  fn foo(_1: u8) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13
+      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +0:19
+      let mut _2: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17
+      let mut _3: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17
+          StorageLive(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16
+          _3 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16
+          _2 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17
+                                           // mir::Constant
+                                           // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14
+                                           // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageDead(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:16: +2:17
+          _1 = move _2;                    // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:17
+          StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:+2:16: +2:17
+          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +3:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:+3:2: +3:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.rs b/tests/mir-opt/copy-prop/copy_propagation_arg.rs
new file mode 100644 (file)
index 0000000..cc98985
--- /dev/null
@@ -0,0 +1,40 @@
+// Check that CopyProp does not propagate an assignment to a function argument
+// (doing so can break usages of the original argument value)
+// unit-test: CopyProp
+fn dummy(x: u8) -> u8 {
+    x
+}
+
+// EMIT_MIR copy_propagation_arg.foo.CopyProp.diff
+fn foo(mut x: u8) {
+    // calling `dummy` to make a use of `x` that copyprop cannot eliminate
+    x = dummy(x); // this will assign a local to `x`
+}
+
+// EMIT_MIR copy_propagation_arg.bar.CopyProp.diff
+fn bar(mut x: u8) {
+    dummy(x);
+    x = 5;
+}
+
+// EMIT_MIR copy_propagation_arg.baz.CopyProp.diff
+fn baz(mut x: i32) -> i32 {
+    // self-assignment to a function argument should be eliminated
+    x = x;
+    x
+}
+
+// EMIT_MIR copy_propagation_arg.arg_src.CopyProp.diff
+fn arg_src(mut x: i32) -> i32 {
+    let y = x;
+    x = 123; // Don't propagate this assignment to `y`
+    y
+}
+
+fn main() {
+    // Make sure the function actually gets instantiated.
+    foo(0);
+    bar(0);
+    baz(0);
+    arg_src(0);
+}
diff --git a/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff b/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff
new file mode 100644 (file)
index 0000000..bc5083e
--- /dev/null
@@ -0,0 +1,60 @@
+- // MIR for `main` before CopyProp
++ // MIR for `main` after CopyProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/cycle.rs:+0:11: +0:11
+      let mut _1: i32;                     // in scope 0 at $DIR/cycle.rs:+1:9: +1:14
+      let mut _4: i32;                     // in scope 0 at $DIR/cycle.rs:+4:9: +4:10
+      let _5: ();                          // in scope 0 at $DIR/cycle.rs:+6:5: +6:12
+      let mut _6: i32;                     // in scope 0 at $DIR/cycle.rs:+6:10: +6:11
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/cycle.rs:+1:9: +1:14
+          let _2: i32;                     // in scope 1 at $DIR/cycle.rs:+2:9: +2:10
+          scope 2 {
+              debug y => _2;               // in scope 2 at $DIR/cycle.rs:+2:9: +2:10
+              let _3: i32;                 // in scope 2 at $DIR/cycle.rs:+3:9: +3:10
+              scope 3 {
+-                 debug z => _3;           // in scope 3 at $DIR/cycle.rs:+3:9: +3:10
++                 debug z => _2;           // in scope 3 at $DIR/cycle.rs:+3:9: +3:10
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/cycle.rs:+1:9: +1:14
+          _1 = val() -> bb1;               // scope 0 at $DIR/cycle.rs:+1:17: +1:22
+                                           // mir::Constant
+                                           // + span: $DIR/cycle.rs:9:17: 9:20
+                                           // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageLive(_2);                 // scope 1 at $DIR/cycle.rs:+2:9: +2:10
+          _2 = _1;                         // scope 1 at $DIR/cycle.rs:+2:13: +2:14
+-         StorageLive(_3);                 // scope 2 at $DIR/cycle.rs:+3:9: +3:10
+-         _3 = _2;                         // scope 2 at $DIR/cycle.rs:+3:13: +3:14
+-         StorageLive(_4);                 // scope 3 at $DIR/cycle.rs:+4:9: +4:10
+-         _4 = _3;                         // scope 3 at $DIR/cycle.rs:+4:9: +4:10
+-         _1 = move _4;                    // scope 3 at $DIR/cycle.rs:+4:5: +4:10
+-         StorageDead(_4);                 // scope 3 at $DIR/cycle.rs:+4:9: +4:10
++         _1 = _2;                         // scope 3 at $DIR/cycle.rs:+4:5: +4:10
+          StorageLive(_5);                 // scope 3 at $DIR/cycle.rs:+6:5: +6:12
+          StorageLive(_6);                 // scope 3 at $DIR/cycle.rs:+6:10: +6:11
+          _6 = _1;                         // scope 3 at $DIR/cycle.rs:+6:10: +6:11
+          _5 = std::mem::drop::<i32>(move _6) -> bb2; // scope 3 at $DIR/cycle.rs:+6:5: +6:12
+                                           // mir::Constant
+                                           // + span: $DIR/cycle.rs:14:5: 14:9
+                                           // + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          StorageDead(_6);                 // scope 3 at $DIR/cycle.rs:+6:11: +6:12
+          StorageDead(_5);                 // scope 3 at $DIR/cycle.rs:+6:12: +6:13
+          _0 = const ();                   // scope 0 at $DIR/cycle.rs:+0:11: +7:2
+-         StorageDead(_3);                 // scope 2 at $DIR/cycle.rs:+7:1: +7:2
+-         StorageDead(_2);                 // scope 1 at $DIR/cycle.rs:+7:1: +7:2
+          StorageDead(_1);                 // scope 0 at $DIR/cycle.rs:+7:1: +7:2
+          return;                          // scope 0 at $DIR/cycle.rs:+7:2: +7:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/cycle.rs b/tests/mir-opt/copy-prop/cycle.rs
new file mode 100644 (file)
index 0000000..b74c397
--- /dev/null
@@ -0,0 +1,15 @@
+//! Tests that cyclic assignments don't hang CopyProp, and result in reasonable code.
+// unit-test: CopyProp
+fn val() -> i32 {
+    1
+}
+
+// EMIT_MIR cycle.main.CopyProp.diff
+fn main() {
+    let mut x = val();
+    let y = x;
+    let z = y;
+    x = z;
+
+    drop(x);
+}
diff --git a/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.mir b/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.mir
new file mode 100644 (file)
index 0000000..918817d
--- /dev/null
@@ -0,0 +1,30 @@
+// MIR for `f` after CopyProp
+
+fn f(_1: usize) -> usize {
+    debug a => _1;                       // in scope 0 at $DIR/dead_stores_79191.rs:+0:6: +0:11
+    let mut _0: usize;                   // return place in scope 0 at $DIR/dead_stores_79191.rs:+0:23: +0:28
+    let _2: usize;                       // in scope 0 at $DIR/dead_stores_79191.rs:+1:9: +1:10
+    let mut _3: usize;                   // in scope 0 at $DIR/dead_stores_79191.rs:+3:9: +3:10
+    let mut _4: usize;                   // in scope 0 at $DIR/dead_stores_79191.rs:+4:8: +4:9
+    scope 1 {
+        debug b => _2;                   // in scope 1 at $DIR/dead_stores_79191.rs:+1:9: +1:10
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/dead_stores_79191.rs:+1:9: +1:10
+        _2 = _1;                         // scope 0 at $DIR/dead_stores_79191.rs:+1:13: +1:14
+        _1 = const 5_usize;              // scope 1 at $DIR/dead_stores_79191.rs:+2:5: +2:10
+        _1 = _2;                         // scope 1 at $DIR/dead_stores_79191.rs:+3:5: +3:10
+        StorageLive(_4);                 // scope 1 at $DIR/dead_stores_79191.rs:+4:8: +4:9
+        _4 = _1;                         // scope 1 at $DIR/dead_stores_79191.rs:+4:8: +4:9
+        _0 = id::<usize>(move _4) -> bb1; // scope 1 at $DIR/dead_stores_79191.rs:+4:5: +4:10
+                                         // mir::Constant
+                                         // + span: $DIR/dead_stores_79191.rs:12:5: 12:7
+                                         // + literal: Const { ty: fn(usize) -> usize {id::<usize>}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        StorageDead(_4);                 // scope 1 at $DIR/dead_stores_79191.rs:+4:9: +4:10
+        return;                          // scope 0 at $DIR/dead_stores_79191.rs:+5:2: +5:2
+    }
+}
diff --git a/tests/mir-opt/copy-prop/dead_stores_79191.rs b/tests/mir-opt/copy-prop/dead_stores_79191.rs
new file mode 100644 (file)
index 0000000..e3493b8
--- /dev/null
@@ -0,0 +1,17 @@
+// unit-test: CopyProp
+
+fn id<T>(x: T) -> T {
+    x
+}
+
+// EMIT_MIR dead_stores_79191.f.CopyProp.after.mir
+fn f(mut a: usize) -> usize {
+    let b = a;
+    a = 5;
+    a = b;
+    id(a)
+}
+
+fn main() {
+    f(0);
+}
diff --git a/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.mir b/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.mir
new file mode 100644 (file)
index 0000000..cf21fad
--- /dev/null
@@ -0,0 +1,30 @@
+// MIR for `f` after CopyProp
+
+fn f(_1: usize) -> usize {
+    debug a => _1;                       // in scope 0 at $DIR/dead_stores_better.rs:+0:10: +0:15
+    let mut _0: usize;                   // return place in scope 0 at $DIR/dead_stores_better.rs:+0:27: +0:32
+    let _2: usize;                       // in scope 0 at $DIR/dead_stores_better.rs:+1:9: +1:10
+    let mut _3: usize;                   // in scope 0 at $DIR/dead_stores_better.rs:+3:9: +3:10
+    let mut _4: usize;                   // in scope 0 at $DIR/dead_stores_better.rs:+4:8: +4:9
+    scope 1 {
+        debug b => _2;                   // in scope 1 at $DIR/dead_stores_better.rs:+1:9: +1:10
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/dead_stores_better.rs:+1:9: +1:10
+        _2 = _1;                         // scope 0 at $DIR/dead_stores_better.rs:+1:13: +1:14
+        _1 = const 5_usize;              // scope 1 at $DIR/dead_stores_better.rs:+2:5: +2:10
+        _1 = _2;                         // scope 1 at $DIR/dead_stores_better.rs:+3:5: +3:10
+        StorageLive(_4);                 // scope 1 at $DIR/dead_stores_better.rs:+4:8: +4:9
+        _4 = _1;                         // scope 1 at $DIR/dead_stores_better.rs:+4:8: +4:9
+        _0 = id::<usize>(move _4) -> bb1; // scope 1 at $DIR/dead_stores_better.rs:+4:5: +4:10
+                                         // mir::Constant
+                                         // + span: $DIR/dead_stores_better.rs:16:5: 16:7
+                                         // + literal: Const { ty: fn(usize) -> usize {id::<usize>}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        StorageDead(_4);                 // scope 1 at $DIR/dead_stores_better.rs:+4:9: +4:10
+        return;                          // scope 0 at $DIR/dead_stores_better.rs:+5:2: +5:2
+    }
+}
diff --git a/tests/mir-opt/copy-prop/dead_stores_better.rs b/tests/mir-opt/copy-prop/dead_stores_better.rs
new file mode 100644 (file)
index 0000000..8465b3c
--- /dev/null
@@ -0,0 +1,21 @@
+// This is a copy of the `dead_stores_79191` test, except that we turn on DSE. This demonstrates
+// that that pass enables this one to do more optimizations.
+
+// unit-test: CopyProp
+// compile-flags: -Zmir-enable-passes=+DeadStoreElimination
+
+fn id<T>(x: T) -> T {
+    x
+}
+
+// EMIT_MIR dead_stores_better.f.CopyProp.after.mir
+pub fn f(mut a: usize) -> usize {
+    let b = a;
+    a = 5;
+    a = b;
+    id(a)
+}
+
+fn main() {
+    f(0);
+}
diff --git a/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff b/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff
new file mode 100644 (file)
index 0000000..d76bf1c
--- /dev/null
@@ -0,0 +1,40 @@
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+  
+  fn f(_1: T) -> () {
+      debug a => _1;                       // in scope 0 at $DIR/move_arg.rs:+0:19: +0:20
+      let mut _0: ();                      // return place in scope 0 at $DIR/move_arg.rs:+0:25: +0:25
+      let _2: T;                           // in scope 0 at $DIR/move_arg.rs:+1:9: +1:10
+      let _3: ();                          // in scope 0 at $DIR/move_arg.rs:+2:5: +2:12
+      let mut _4: T;                       // in scope 0 at $DIR/move_arg.rs:+2:7: +2:8
+      let mut _5: T;                       // in scope 0 at $DIR/move_arg.rs:+2:10: +2:11
+      scope 1 {
+-         debug b => _2;                   // in scope 1 at $DIR/move_arg.rs:+1:9: +1:10
++         debug b => _1;                   // in scope 1 at $DIR/move_arg.rs:+1:9: +1:10
+      }
+  
+      bb0: {
+-         StorageLive(_2);                 // scope 0 at $DIR/move_arg.rs:+1:9: +1:10
+-         _2 = _1;                         // scope 0 at $DIR/move_arg.rs:+1:13: +1:14
+          StorageLive(_3);                 // scope 1 at $DIR/move_arg.rs:+2:5: +2:12
+-         StorageLive(_4);                 // scope 1 at $DIR/move_arg.rs:+2:7: +2:8
+-         _4 = _1;                         // scope 1 at $DIR/move_arg.rs:+2:7: +2:8
+-         StorageLive(_5);                 // scope 1 at $DIR/move_arg.rs:+2:10: +2:11
+-         _5 = _2;                         // scope 1 at $DIR/move_arg.rs:+2:10: +2:11
+-         _3 = g::<T>(move _4, move _5) -> bb1; // scope 1 at $DIR/move_arg.rs:+2:5: +2:12
++         _3 = g::<T>(_1, _1) -> bb1;      // scope 1 at $DIR/move_arg.rs:+2:5: +2:12
+                                           // mir::Constant
+                                           // + span: $DIR/move_arg.rs:7:5: 7:6
+                                           // + literal: Const { ty: fn(T, T) {g::<T>}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+-         StorageDead(_5);                 // scope 1 at $DIR/move_arg.rs:+2:11: +2:12
+-         StorageDead(_4);                 // scope 1 at $DIR/move_arg.rs:+2:11: +2:12
+          StorageDead(_3);                 // scope 1 at $DIR/move_arg.rs:+2:12: +2:13
+          _0 = const ();                   // scope 0 at $DIR/move_arg.rs:+0:25: +3:2
+-         StorageDead(_2);                 // scope 0 at $DIR/move_arg.rs:+3:1: +3:2
+          return;                          // scope 0 at $DIR/move_arg.rs:+3:2: +3:2
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/move_arg.rs b/tests/mir-opt/copy-prop/move_arg.rs
new file mode 100644 (file)
index 0000000..40ae1d8
--- /dev/null
@@ -0,0 +1,15 @@
+// Test that we do not move multiple times from the same local.
+// unit-test: CopyProp
+
+// EMIT_MIR move_arg.f.CopyProp.diff
+pub fn f<T: Copy>(a: T) {
+    let b = a;
+    g(a, b);
+}
+
+#[inline(never)]
+pub fn g<T: Copy>(_: T, _: T) {}
+
+fn main() {
+    f(5)
+}
diff --git a/tests/mir-opt/copy-prop/mutate_through_pointer.f.CopyProp.diff b/tests/mir-opt/copy-prop/mutate_through_pointer.f.CopyProp.diff
new file mode 100644 (file)
index 0000000..61fdd6f
--- /dev/null
@@ -0,0 +1,19 @@
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+  
+  fn f(_1: bool) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/mutate_through_pointer.rs:+0:18: +0:22
+      let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+      let mut _3: *const bool;             // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+      let mut _4: *mut bool;               // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+  
+      bb0: {
+          _2 = _1;                         // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          _3 = &raw const _2;              // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          _4 = &raw mut (*_3);             // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+          (*_4) = const false;             // scope 0 at $DIR/mutate_through_pointer.rs:+5:9: +5:20
+          _0 = _1;                         // scope 0 at $DIR/mutate_through_pointer.rs:+6:9: +6:16
+          return;                          // scope 0 at $DIR/mutate_through_pointer.rs:+7:9: +7:17
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/mutate_through_pointer.rs b/tests/mir-opt/copy-prop/mutate_through_pointer.rs
new file mode 100644 (file)
index 0000000..609e49d
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(custom_mir, core_intrinsics)]
+#![allow(unused_assignments)]
+extern crate core;
+use core::intrinsics::mir::*;
+
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn f(c: bool) -> bool {
+    mir!({
+        let a = c;
+        let p = core::ptr::addr_of!(a);
+        let p2 = core::ptr::addr_of_mut!(*p);
+        *p2 = false;
+        RET = c;
+        Return()
+    })
+}
+
+fn main() {
+    assert_eq!(true, f(true));
+}
+
+// EMIT_MIR mutate_through_pointer.f.CopyProp.diff
diff --git a/tests/mir-opt/copy-prop/non_dominate.f.CopyProp.diff b/tests/mir-opt/copy-prop/non_dominate.f.CopyProp.diff
new file mode 100644 (file)
index 0000000..9760fd3
--- /dev/null
@@ -0,0 +1,29 @@
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+  
+  fn f(_1: bool) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/non_dominate.rs:+0:18: +0:22
+      let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+      let mut _3: bool;                    // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+  
+      bb0: {
+          goto -> bb1;                     // scope 0 at $DIR/non_dominate.rs:+4:11: +4:20
+      }
+  
+      bb1: {
+          _3 = _1;                         // scope 0 at $DIR/non_dominate.rs:+5:17: +5:22
+          switchInt(_3) -> [0: bb3, otherwise: bb2]; // scope 0 at $DIR/non_dominate.rs:+5:24: +5:58
+      }
+  
+      bb2: {
+          _2 = _3;                         // scope 0 at $DIR/non_dominate.rs:+8:17: +8:22
+          _1 = const false;                // scope 0 at $DIR/non_dominate.rs:+8:24: +8:33
+          goto -> bb1;                     // scope 0 at $DIR/non_dominate.rs:+8:35: +8:44
+      }
+  
+      bb3: {
+          _0 = _2;                         // scope 0 at $DIR/non_dominate.rs:+9:17: +9:24
+          return;                          // scope 0 at $DIR/non_dominate.rs:+9:26: +9:34
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/non_dominate.rs b/tests/mir-opt/copy-prop/non_dominate.rs
new file mode 100644 (file)
index 0000000..c0ea838
--- /dev/null
@@ -0,0 +1,26 @@
+// unit-test: CopyProp
+
+#![feature(custom_mir, core_intrinsics)]
+#![allow(unused_assignments)]
+extern crate core;
+use core::intrinsics::mir::*;
+
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn f(c: bool) -> bool {
+    mir!(
+        let a: bool;
+        let b: bool;
+        { Goto(bb1) }
+        bb1 = { b = c; match b { false => bb3, _ => bb2 }}
+        // This assignment to `a` does not dominate the use in `bb3`.
+        // It should not be replaced by `b`.
+        bb2 = { a = b; c = false; Goto(bb1) }
+        bb3 = { RET = a; Return() }
+    )
+}
+
+fn main() {
+    assert_eq!(true, f(true));
+}
+
+// EMIT_MIR non_dominate.f.CopyProp.diff
index 02aafd7acc4ca5660cae57c17a18394031362f13..6870d7d6c45b457b8459dce4a63f514fdb4cbdc8 100644 (file)
           _1 = const u8::MAX;              // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
           StorageLive(_2);                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
           _2 = const 1_u8;                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
-          StorageLive(_3);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          _3 = const u8::MAX;              // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          StorageLive(_4);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          _4 = const 1_u8;                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
           _5 = CheckedAdd(const u8::MAX, const 1_u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
           assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> bb1; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
       }
   
       bb1: {
-          StorageDead(_4);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          StorageDead(_3);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          StorageDead(_2);                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
-          StorageDead(_1);                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
           return;                          // scope 0 at $DIR/inherit_overflow.rs:+4:2: +4:2
       }
   }
index d7f66a6bf4d56816ba163731a309910cfe2d39c6..1a7fb916e56dbaf3d8ba15a4e84b422557117c16 100644 (file)
@@ -11,7 +11,7 @@ fn const_dividend(_1: i32) -> i32 {
     }
 
     bb1: {
-        _0 = Div(const 256_i32, move _1); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+        _0 = Div(const 256_i32, _1);     // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
         return;                          // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2
     }
 }
index 7b7ab1978258fe21c9adf5f2c2e49e79b473ca5e..5526a194be563cb8ab98f4c0b4cab1669ed90ef4 100644 (file)
@@ -5,7 +5,7 @@ fn const_divisor(_1: i32) -> i32 {
     let mut _0: i32;                     // return place in scope 0 at $DIR/div_overflow.rs:+0:33: +0:36
 
     bb0: {
-        _0 = Div(move _1, const 256_i32); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+        _0 = Div(_1, const 256_i32);     // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
         return;                          // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2
     }
 }
index c1c2cde71ab5b38f485885cd7f3a60bc4f13ad37..df9f8dcf1a407b7496b9f719db0d88d374162b5c 100644 (file)
           _10 = ((_7 as Some).0: usize);   // scope 3 at $DIR/funky_arms.rs:+13:17: +13:26
           StorageLive(_11);                // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46
           _11 = &mut (*_1);                // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46
-          StorageLive(_12);                // scope 3 at $DIR/funky_arms.rs:+15:48: +15:51
-          _12 = _2;                        // scope 3 at $DIR/funky_arms.rs:+15:48: +15:51
           StorageLive(_13);                // scope 3 at $DIR/funky_arms.rs:+15:53: +15:57
           _13 = _6;                        // scope 3 at $DIR/funky_arms.rs:+15:53: +15:57
           StorageLive(_14);                // scope 3 at $DIR/funky_arms.rs:+15:59: +15:79
           StorageLive(_15);                // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75
-          StorageLive(_16);                // scope 3 at $DIR/funky_arms.rs:+15:59: +15:68
-          _16 = _10;                       // scope 3 at $DIR/funky_arms.rs:+15:59: +15:68
-          _15 = move _16 as u32 (IntToInt); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75
-          StorageDead(_16);                // scope 3 at $DIR/funky_arms.rs:+15:74: +15:75
+          _15 = _10 as u32 (IntToInt);     // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75
           _14 = Add(move _15, const 1_u32); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:79
           StorageDead(_15);                // scope 3 at $DIR/funky_arms.rs:+15:78: +15:79
-          StorageLive(_17);                // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86
-          _17 = _3;                        // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86
-          _0 = float_to_exponential_common_exact::<T>(move _11, move _12, move _13, move _14, move _17) -> bb7; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87
+          _0 = float_to_exponential_common_exact::<T>(move _11, _2, move _13, move _14, _3) -> bb7; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87
                                            // mir::Constant
                                            // + span: $DIR/funky_arms.rs:26:9: 26:42
                                            // + literal: Const { ty: for<'a, 'b, 'c> fn(&'a mut Formatter<'b>, &'c T, Sign, u32, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_exact::<T>}, val: Value(<ZST>) }
       }
   
       bb7: {
-          StorageDead(_17);                // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
           StorageDead(_14);                // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
           StorageDead(_13);                // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
-          StorageDead(_12);                // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
           StorageDead(_11);                // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
-          StorageDead(_10);                // scope 2 at $DIR/funky_arms.rs:+16:5: +16:6
           goto -> bb10;                    // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6
       }
   
       bb8: {
           StorageLive(_18);                // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49
           _18 = &mut (*_1);                // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49
-          StorageLive(_19);                // scope 2 at $DIR/funky_arms.rs:+17:51: +17:54
-          _19 = _2;                        // scope 2 at $DIR/funky_arms.rs:+17:51: +17:54
           StorageLive(_20);                // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60
           _20 = _6;                        // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60
-          StorageLive(_21);                // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67
-          _21 = _3;                        // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67
-          _0 = float_to_exponential_common_shortest::<T>(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68
+          _0 = float_to_exponential_common_shortest::<T>(move _18, _2, move _20, _3) -> bb9; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68
                                            // mir::Constant
                                            // + span: $DIR/funky_arms.rs:28:9: 28:45
                                            // + literal: Const { ty: for<'a, 'b, 'c> fn(&'a mut Formatter<'b>, &'c T, Sign, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_shortest::<T>}, val: Value(<ZST>) }
       }
   
       bb9: {
-          StorageDead(_21);                // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68
           StorageDead(_20);                // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68
-          StorageDead(_19);                // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68
           StorageDead(_18);                // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68
           goto -> bb10;                    // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6
       }
index a8e090020c3d31bb70ee083e59d02adc982a4d36..afe518642146fcd0c40e9b63678fabe8137e5812 100644 (file)
@@ -1,7 +1,14 @@
 // MIR for `main::{closure#0}` 0 generator_drop
 /* generator_layout = GeneratorLayout {
     field_tys: {
-        _0: std::string::String,
+        _0: GeneratorSavedTy {
+            ty: std::string::String,
+            source_info: SourceInfo {
+                span: $DIR/generator_drop_cleanup.rs:11:13: 11:15 (#0),
+                scope: scope[0],
+            },
+            ignore_for_traits: false,
+        },
     },
     variant_fields: {
         Unresumed(0): [],
index b3d3c768a5dd9a22ded6107eec3ec9f87c196c3c..2f096c3e0a189e07c2b25dab943efc4f9e03b119 100644 (file)
@@ -1,7 +1,14 @@
 // MIR for `main::{closure#0}` 0 generator_resume
 /* generator_layout = GeneratorLayout {
     field_tys: {
-        _0: HasDrop,
+        _0: GeneratorSavedTy {
+            ty: HasDrop,
+            source_info: SourceInfo {
+                span: $DIR/generator_tiny.rs:20:13: 20:15 (#0),
+                scope: scope[0],
+            },
+            ignore_for_traits: false,
+        },
     },
     variant_fields: {
         Unresumed(0): [],
index 8ea1a0757f2f028ee79cb76c8ddd08f4f29dc5d2..64c3e47ff46edb7b40ca5853b413e2773923d3ac 100644 (file)
@@ -35,8 +35,8 @@
           _4 = &(*_2);                     // scope 1 at $DIR/dyn_trait.rs:+2:23: +2:24
 -         _0 = try_execute_query::<<Q as Query>::C>(move _4) -> bb2; // scope 1 at $DIR/dyn_trait.rs:+2:5: +2:25
 +         StorageLive(_5);                 // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
-+         _5 = move _4 as &dyn Cache<V = <Q as Query>::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
-+         _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(move _5) -> bb2; // scope 3 at $DIR/dyn_trait.rs:21:5: 21:22
++         _5 = _4 as &dyn Cache<V = <Q as Query>::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
++         _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(_5) -> bb2; // scope 3 at $DIR/dyn_trait.rs:21:5: 21:22
                                            // mir::Constant
 -                                          // + span: $DIR/dyn_trait.rs:34:5: 34:22
 -                                          // + literal: Const { ty: for<'a> fn(&'a <Q as Query>::C) {try_execute_query::<<Q as Query>::C>}, val: Value(<ZST>) }
index a71d73b7453544464922e3434b41b858aa18836b..3fa9c3e88f6349b265f00d3f0d3b91eb9707f50d 100644 (file)
@@ -17,7 +17,7 @@
           _2 = move _3 as &dyn Cache<V = <C as Cache>::V> (Pointer(Unsize)); // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
           StorageDead(_3);                 // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
 -         _0 = mk_cycle::<<C as Cache>::V>(move _2) -> bb1; // scope 0 at $DIR/dyn_trait.rs:+1:5: +1:16
-+         _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(move _2) -> bb1; // scope 1 at $DIR/dyn_trait.rs:21:5: 21:22
++         _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(_2) -> bb1; // scope 1 at $DIR/dyn_trait.rs:21:5: 21:22
                                            // mir::Constant
 -                                          // + span: $DIR/dyn_trait.rs:27:5: 27:13
 -                                          // + literal: Const { ty: for<'a> fn(&'a (dyn Cache<V = <C as Cache>::V> + 'a)) {mk_cycle::<<C as Cache>::V>}, val: Value(<ZST>) }
index 3502c25864bf9fffe84742a443c7876e4a770b95..20f737cc29f62904d92d2c6eaed05d054610357b 100644 (file)
@@ -26,7 +26,7 @@ fn bar() -> bool {
         _3 = const 1_i32;                // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
         StorageLive(_4);                 // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
         _4 = const -1_i32;               // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
-        _0 = Eq(move _3, move _4);       // scope 2 at $DIR/inline_any_operand.rs:17:5: 17:11
+        _0 = Eq(_3, _4);                 // scope 2 at $DIR/inline_any_operand.rs:17:5: 17:11
         StorageDead(_4);                 // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
         StorageDead(_3);                 // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
         StorageDead(_2);                 // scope 1 at $DIR/inline_any_operand.rs:+2:12: +2:13
index f27b64c305457a14b2da1b198d86a2b922980875..57574acf92354e375130f3997eb20351aa41309d 100644 (file)
@@ -92,7 +92,7 @@
 + 
 +     bb3: {
 +         StorageLive(_8);                 // scope 6 at $DIR/inline_generator.rs:15:17: 15:39
-+         switchInt(move _7) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21
++         switchInt(_7) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21
 +     }
 + 
 +     bb4: {
 +         StorageLive(_8);                 // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
 +         StorageDead(_8);                 // scope 6 at $DIR/inline_generator.rs:15:38: 15:39
 +         Deinit(_1);                      // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
-+         ((_1 as Complete).0: bool) = move _7; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
++         ((_1 as Complete).0: bool) = _7; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
 +         discriminant(_1) = 1;            // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
 +         _12 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
 +         discriminant((*_12)) = 1;        // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
index 2a4dc9e3e809919ed553686727fbb420e1594fb4..a28da146e378659e68193505aeba97c8cb3d0d08 100644 (file)
       let mut _6: ();                      // in scope 0 at $DIR/inline_into_box_place.rs:+1:42: +1:43
       let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
 +     let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
++     let mut _9: std::vec::Vec<u32>;      // in scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
       scope 1 {
           debug _x => _1;                  // in scope 1 at $DIR/inline_into_box_place.rs:+1:9: +1:11
       }
       scope 2 {
       }
 +     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline_into_box_place.rs:8:33: 8:43
-+         let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         let mut _10: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +     }
   
       bb0: {
@@ -37,8 +38,9 @@
 -         (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
 +         StorageLive(_8);                 // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
 +         _8 = &mut (*_7);                 // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
-+         StorageLive(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         _9 = const _;                    // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageLive(_9);                 // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
++         StorageLive(_10);                // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         _10 = const _;                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
                                            // mir::Constant
 -                                          // + span: $DIR/inline_into_box_place.rs:8:33: 8:41
 -                                          // + user_ty: UserType(1)
 +                                          // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+         Deinit((*_8));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         Deinit(_9);                      // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         (_9.0: alloc::raw_vec::RawVec<u32>) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         (_9.1: usize) = const 0_usize;   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_10);                // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         (*_8) = move _9;                 // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
++         StorageDead(_9);                 // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
 +         StorageDead(_8);                 // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
           _1 = move _5;                    // scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
           StorageDead(_5);                 // scope 0 at $DIR/inline_into_box_place.rs:+1:42: +1:43
index 73aea719eed51956d3996950160b124a2217a360..b7c5bbecb6883a97306779d8f5e65278fe511dea 100644 (file)
@@ -15,7 +15,7 @@ fn test2(_1: &dyn X) -> bool {
         _3 = &(*_1);                     // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
         _2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
         StorageDead(_3);                 // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
-        _0 = <dyn X as X>::y(move _2) -> bb1; // scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10
+        _0 = <dyn X as X>::y(_2) -> bb1; // scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10
                                          // mir::Constant
                                          // + span: $DIR/inline_trait_method_2.rs:10:7: 10:8
                                          // + literal: Const { ty: for<'a> fn(&'a dyn X) -> bool {<dyn X as X>::y}, val: Value(<ZST>) }
diff --git a/tests/mir-opt/inline/issue_106141.outer.Inline.diff b/tests/mir-opt/inline/issue_106141.outer.Inline.diff
new file mode 100644 (file)
index 0000000..97361fa
--- /dev/null
@@ -0,0 +1,55 @@
+- // MIR for `outer` before Inline
++ // MIR for `outer` after Inline
+  
+  fn outer() -> usize {
+      let mut _0: usize;                   // return place in scope 0 at $DIR/issue_106141.rs:+0:19: +0:24
++     scope 1 (inlined inner) {            // at $DIR/issue_106141.rs:2:5: 2:12
++         let mut _1: bool;                // in scope 1 at $DIR/issue_106141.rs:13:8: 13:21
++         let mut _2: bool;                // in scope 1 at $DIR/issue_106141.rs:13:8: 13:21
++         let mut _3: &[bool; 1];          // in scope 1 at $DIR/issue_106141.rs:11:18: 11:25
++         scope 2 {
++             debug buffer => _3;          // in scope 2 at $DIR/issue_106141.rs:11:9: 11:15
++             scope 3 {
++                 debug index => _0;       // in scope 3 at $DIR/issue_106141.rs:12:9: 12:14
++             }
++         }
++     }
+  
+      bb0: {
+-         _0 = inner() -> bb1;             // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
++         StorageLive(_3);                 // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
++         _3 = const _;                    // scope 1 at $DIR/issue_106141.rs:11:18: 11:25
+                                           // mir::Constant
+-                                          // + span: $DIR/issue_106141.rs:2:5: 2:10
+-                                          // + literal: Const { ty: fn() -> usize {inner}, val: Value(<ZST>) }
++                                          // + span: $DIR/issue_106141.rs:11:18: 11:25
++                                          // + literal: Const { ty: &[bool; 1], val: Unevaluated(inner, [], Some(promoted[0])) }
++         _0 = index() -> bb1;             // scope 2 at $DIR/issue_106141.rs:12:17: 12:24
++                                          // mir::Constant
++                                          // + span: $DIR/issue_106141.rs:12:17: 12:22
++                                          // + literal: Const { ty: fn() -> usize {index}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
++         StorageLive(_1);                 // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++         _2 = Lt(_0, const 1_usize);      // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++         assert(move _2, "index out of bounds: the length is {} but the index is {}", const 1_usize, _0) -> bb2; // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++     }
++ 
++     bb2: {
++         _1 = (*_3)[_0];                  // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++         switchInt(move _1) -> [0: bb3, otherwise: bb4]; // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++     }
++ 
++     bb3: {
++         _0 = const 0_usize;              // scope 3 at $DIR/issue_106141.rs:16:9: 16:10
++         goto -> bb4;                     // scope 3 at $DIR/issue_106141.rs:13:5: 17:6
++     }
++ 
++     bb4: {
++         StorageDead(_1);                 // scope 3 at $DIR/issue_106141.rs:17:5: 17:6
++         StorageDead(_3);                 // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
+          return;                          // scope 0 at $DIR/issue_106141.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/issue_106141.rs b/tests/mir-opt/inline/issue_106141.rs
new file mode 100644 (file)
index 0000000..c8288b7
--- /dev/null
@@ -0,0 +1,24 @@
+pub fn outer() -> usize {
+    inner()
+}
+
+fn index() -> usize {
+    loop {}
+}
+
+#[inline]
+fn inner() -> usize {
+    let buffer = &[true];
+    let index = index();
+    if buffer[index] {
+        index
+    } else {
+        0
+    }
+}
+
+fn main() {
+    outer();
+}
+
+// EMIT_MIR issue_106141.outer.Inline.diff
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>();
+}
index b2706e5a436e2f02ae3084d8a75cb49b68a2c563..30bf2c0684e52525ba75d3da0232559318bd75f4 100644 (file)
@@ -15,7 +15,7 @@
       let mut _10: (u32, bool);            // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
       let mut _11: (u32, bool);            // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       scope 1 (inlined imm8) {             // at $DIR/issue_101973.rs:14:5: 14:17
-          debug x => _5;                   // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14
+          debug x => _1;                   // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14
           let mut _12: u32;                // in scope 1 at $DIR/issue_101973.rs:7:12: 7:27
           let mut _13: u32;                // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20
           let mut _14: (u32, bool);        // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20
           StorageLive(_2);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65
           StorageLive(_3);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:58
           StorageLive(_4);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:17
-          StorageLive(_5);                 // scope 0 at $DIR/issue_101973.rs:+1:10: +1:16
-          _5 = _1;                         // scope 0 at $DIR/issue_101973.rs:+1:10: +1:16
           StorageLive(_12);                // scope 2 at $DIR/issue_101973.rs:7:12: 7:27
           StorageLive(_13);                // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
-          _14 = CheckedShr(_5, const 0_i32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
+          _14 = CheckedShr(_1, const 0_i32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
           assert(!move (_14.1: bool), "attempt to shift right by `{}`, which would overflow", const 0_i32) -> bb3; // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
       }
   
       bb1: {
           _8 = move (_10.0: u32);          // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-          StorageDead(_9);                 // scope 0 at $DIR/issue_101973.rs:+1:44: +1:45
           _7 = BitAnd(move _8, const 15_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
           StorageDead(_8);                 // scope 0 at $DIR/issue_101973.rs:+1:51: +1:52
           _11 = CheckedShl(_7, const 1_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       bb2: {
           _6 = move (_11.0: u32);          // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
           StorageDead(_7);                 // scope 0 at $DIR/issue_101973.rs:+1:56: +1:57
-          StorageLive(_15);                // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-          _15 = _4;                        // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-          StorageLive(_16);                // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-          _16 = _6;                        // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-          _3 = rotate_right::<u32>(move _15, move _16) -> bb4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+          _3 = rotate_right::<u32>(_4, _6) -> bb4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
                                            // + literal: Const { ty: extern "rust-intrinsic" fn(u32, u32) -> u32 {rotate_right::<u32>}, val: Value(<ZST>) }
           StorageDead(_13);                // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
           _4 = BitOr(const 0_u32, move _12); // scope 2 at $DIR/issue_101973.rs:7:5: 7:27
           StorageDead(_12);                // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
-          StorageDead(_5);                 // scope 0 at $DIR/issue_101973.rs:+1:16: +1:17
           StorageLive(_6);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
           StorageLive(_7);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
           StorageLive(_8);                 // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-          StorageLive(_9);                 // scope 0 at $DIR/issue_101973.rs:+1:33: +1:39
-          _9 = _1;                         // scope 0 at $DIR/issue_101973.rs:+1:33: +1:39
-          _10 = CheckedShr(_9, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+          _10 = CheckedShr(_1, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
           assert(!move (_10.1: bool), "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
       }
   
       bb4: {
-          StorageDead(_16);                // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-          StorageDead(_15);                // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-          StorageDead(_6);                 // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58
-          StorageDead(_4);                 // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58
           _2 = move _3 as i32 (IntToInt);  // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65
           StorageDead(_3);                 // scope 0 at $DIR/issue_101973.rs:+1:64: +1:65
           _0 = move _2 as i64 (IntToInt);  // scope 0 at $DIR/issue_101973.rs:+1:5: +1:72
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 c24543daeacb7939e50261e7f38a4ba7dab1e932..c14780052fb091f257fefbd178c0c05357f2c7c7 100644 (file)
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/issue_76432.rs:+1:9: +1:10
-          StorageLive(_3);                 // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
           StorageLive(_4);                 // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
           StorageLive(_5);                 // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29
-          StorageLive(_6);                 // scope 0 at $DIR/issue_76432.rs:+1:21: +1:22
-          _6 = _1;                         // scope 0 at $DIR/issue_76432.rs:+1:21: +1:22
-          StorageLive(_7);                 // scope 0 at $DIR/issue_76432.rs:+1:24: +1:25
-          _7 = _1;                         // scope 0 at $DIR/issue_76432.rs:+1:24: +1:25
-          StorageLive(_8);                 // scope 0 at $DIR/issue_76432.rs:+1:27: +1:28
-          _8 = _1;                         // scope 0 at $DIR/issue_76432.rs:+1:27: +1:28
-          _5 = [move _6, move _7, move _8]; // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29
-          StorageDead(_8);                 // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
-          StorageDead(_7);                 // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
-          StorageDead(_6);                 // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
+          _5 = [_1, _1, _1];               // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29
           _4 = &_5;                        // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
-          _3 = _4;                         // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
-          _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
-          StorageDead(_3);                 // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
-          StorageDead(_4);                 // scope 0 at $DIR/issue_76432.rs:+1:29: +1:30
+          _2 = _4 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
           _9 = Len((*_2));                 // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
           _10 = const 3_usize;             // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
 -         _11 = Eq(move _9, const 3_usize); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
index 1c69a6232d60631e30f8b36dc538819916abf6bc..93804780371cd41d11207b768bdad81a67f63269 100644 (file)
@@ -26,7 +26,7 @@
           _3 = _1;                         // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
           _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53
                                            // mir::Constant
-                                           // + span: $DIR/issue_75439.rs:7:37: 7:46
+                                           // + span: $DIR/issue_75439.rs:8:37: 8:46
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) }
       }
   
@@ -49,7 +49,7 @@
           _6 = _4;                         // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
           _5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36
                                            // mir::Constant
-                                           // + span: $DIR/issue_75439.rs:10:23: 10:32
+                                           // + span: $DIR/issue_75439.rs:11:23: 11:32
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) }
       }
   
index ae2e036312e88373f7f3804d191bed8932afc681..4c749a150c091f5159defd11c28594e7cd22633c 100644 (file)
@@ -1,4 +1,5 @@
 // EMIT_MIR issue_75439.foo.MatchBranchSimplification.diff
+// ignore-endian-big
 
 use std::mem::transmute;
 
index 701c2ad705af2997fdf4e501f706819260a5bd27..dee1d538395ef86b9b5ec4b86666ae6478b72943 100644 (file)
@@ -5,27 +5,23 @@ fn array_bound(_1: usize, _2: &[u8; N]) -> u8 {
     debug slice => _2;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:50: +0:55
     let mut _0: u8;                      // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:70: +0:72
     let mut _3: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
-    let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
-    let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
-    let mut _6: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-    let mut _7: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+    let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+    let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+    let mut _6: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
-        StorageLive(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
-        _4 = _1;                         // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
-        StorageLive(_5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
-        _5 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
-        _3 = Lt(move _4, move _5);       // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
-        StorageDead(_5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+        StorageLive(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+        _4 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+        _3 = Lt(_1, move _4);            // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
         StorageDead(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
         switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
     }
 
     bb1: {
-        _6 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-        _7 = Lt(_1, _6);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-        assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        _5 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        _6 = Lt(_1, _5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
     }
 
     bb2: {
index 0440cfce2893f152437667e746632f89763ecb4b..e35fe758ab12ddea899bddedcba028e5e02fc4c3 100644 (file)
@@ -5,30 +5,26 @@ fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 {
     debug slice => _2;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:54: +0:59
     let mut _0: u8;                      // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:78: +0:80
     let mut _3: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
-    let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
-    let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
-    let mut _6: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-    let mut _7: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-    let _8: usize;                       // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
-    let mut _9: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
-    let mut _10: bool;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+    let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+    let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+    let mut _6: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+    let _7: usize;                       // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+    let mut _8: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+    let mut _9: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
-        StorageLive(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
-        _4 = _1;                         // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
-        StorageLive(_5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
-        _5 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
-        _3 = Lt(move _4, move _5);       // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
-        StorageDead(_5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+        StorageLive(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+        _4 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+        _3 = Lt(_1, move _4);            // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
         StorageDead(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
         switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
     }
 
     bb1: {
-        _6 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-        _7 = Lt(_1, _6);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-        assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        _5 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        _6 = Lt(_1, _5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
     }
 
     bb2: {
@@ -37,16 +33,16 @@ fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 {
     }
 
     bb3: {
-        StorageLive(_8);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
-        _8 = const 0_usize;              // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
-        _9 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
-        _10 = Lt(const 0_usize, _9);     // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
-        assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+        StorageLive(_7);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+        _7 = const 0_usize;              // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+        _8 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+        _9 = Lt(const 0_usize, _8);      // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+        assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
     }
 
     bb4: {
-        (*_2)[_8] = const 42_u8;         // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22
-        StorageDead(_8);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23
+        (*_2)[_7] = const 42_u8;         // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22
+        StorageDead(_7);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23
         _0 = const 42_u8;                // scope 0 at $DIR/lower_array_len_e2e.rs:+6:9: +6:11
         goto -> bb5;                     // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6
     }
index 8e6564a38b0bbbaafe2dfd25125cdb4c2efefaf2..798e45df8ca766f8c0bdf0daac9492cbe7b23944 100644 (file)
@@ -22,7 +22,7 @@
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/region_subtyping_basic.rs:+0:11: +0:11
-    let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x00000003)) }]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
+    let mut _1: [usize; Const(Value(Leaf(0x00000003)): usize)]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
     let _3: usize;                       // in scope 0 at $DIR/region_subtyping_basic.rs:+2:16: +2:17
     let mut _4: usize;                   // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
     let mut _5: bool;                    // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
index 74d44c6741a92747b01cf35d5f7d1b52324ff91e..4767bfc76ed9de92c1632622e26392765d54cb87 100644 (file)
@@ -22,7 +22,7 @@
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/region_subtyping_basic.rs:+0:11: +0:11
-    let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x0000000000000003)) }]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
+    let mut _1: [usize; Const(Value(Leaf(0x0000000000000003)): usize)]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
     let _3: usize;                       // in scope 0 at $DIR/region_subtyping_basic.rs:+2:16: +2:17
     let mut _4: usize;                   // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
     let mut _5: bool;                    // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
index 916f99049c60ab0161473913f89681a1ed0d88d7..760f48d956d6288b3d72ea8edc06ed83e0e3ed90 100644 (file)
@@ -37,7 +37,7 @@ fn ezmap(_1: Option<i32>) -> Option<i32> {
     bb3: {
         _5 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
         StorageLive(_4);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
-        _4 = Add(move _5, const 1_i32);  // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
+        _4 = Add(_5, const 1_i32);       // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
         Deinit(_0);                      // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
         ((_0 as Some).0: i32) = move _4; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
         discriminant(_0) = 1;            // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
index 70bfbf1b3e366473e3dd9fed7c2e3c0500a84790..35ffc4963cb63b4f8d707e2d633ceca9a720548e 100644 (file)
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/simplify_match.rs:+1:11: +1:31
           StorageLive(_2);                 // scope 0 at $DIR/simplify_match.rs:+1:17: +1:18
           _2 = const false;                // scope 0 at $DIR/simplify_match.rs:+1:21: +1:26
--         _1 = _2;                         // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29
-+         _1 = const false;                // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_match.rs:+1:30: +1:31
--         switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
+-         switchInt(_2) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
 +         switchInt(const false) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
       }
   
@@ -32,7 +28,6 @@
       }
   
       bb3: {
-          StorageDead(_1);                 // scope 0 at $DIR/simplify_match.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/simplify_match.rs:+5:2: +5:2
       }
   }
diff --git a/tests/mir-opt/slice_filter.rs b/tests/mir-opt/slice_filter.rs
new file mode 100644 (file)
index 0000000..97c18af
--- /dev/null
@@ -0,0 +1,18 @@
+fn main() {
+    let input = vec![];
+    let _variant_a_result = variant_a(&input);
+    let _variant_b_result = variant_b(&input);
+}
+
+pub fn variant_a(input: &[(usize, usize, usize, usize)]) -> usize {
+    input.iter().filter(|(a, b, c, d)| a <= c && d <= b || c <= a && b <= d).count()
+}
+
+pub fn variant_b(input: &[(usize, usize, usize, usize)]) -> usize {
+    input.iter().filter(|&&(a, b, c, d)| a <= c && d <= b || c <= a && b <= d).count()
+}
+
+// EMIT_MIR slice_filter.variant_a-{closure#0}.CopyProp.diff
+// EMIT_MIR slice_filter.variant_a-{closure#0}.DestinationPropagation.diff
+// EMIT_MIR slice_filter.variant_b-{closure#0}.CopyProp.diff
+// EMIT_MIR slice_filter.variant_b-{closure#0}.DestinationPropagation.diff
diff --git a/tests/mir-opt/slice_filter.variant_a-{closure#0}.CopyProp.diff b/tests/mir-opt/slice_filter.variant_a-{closure#0}.CopyProp.diff
new file mode 100644 (file)
index 0000000..d1f6fd9
--- /dev/null
@@ -0,0 +1,279 @@
+- // MIR for `variant_a::{closure#0}` before CopyProp
++ // MIR for `variant_a::{closure#0}` after CopyProp
+  
+  fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:8:25: 8:39], _2: &&(usize, usize, usize, usize)) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/slice_filter.rs:+0:40: +0:40
+      let _3: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+      let _4: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+      let _5: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+      let _6: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+      let mut _7: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:56
+      let mut _8: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:46
+      let mut _9: &&usize;                 // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:41
+      let mut _10: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46
+      let _11: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46
+      let mut _12: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:56
+      let mut _13: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:51
+      let mut _14: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56
+      let _15: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56
+      let mut _16: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:76
+      let mut _17: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:66
+      let mut _18: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:61
+      let mut _19: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66
+      let _20: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66
+      let mut _21: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:76
+      let mut _22: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:71
+      let mut _23: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+      let _24: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+      let mut _25: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      let mut _26: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      let mut _27: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      let mut _28: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      scope 1 {
+          debug a => _3;                   // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28
+          debug b => _4;                   // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31
+          debug c => _5;                   // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34
+          debug d => _6;                   // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37
+          scope 2 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:40: 8:46
+              debug self => _9;            // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _10;          // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _29: &usize;         // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _30: &usize;         // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _31: &usize;         // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _32: &usize;         // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 3 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug self => _29;       // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug other => _30;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug self => _31;       // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug other => _32;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _33: usize;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _34: usize;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+          scope 4 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:60: 8:66
+              debug self => _18;           // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _19;          // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _35: &usize;         // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _36: &usize;         // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _37: &usize;         // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _38: &usize;         // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 5 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug self => _35;       // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug other => _36;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug self => _37;       // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug other => _38;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _39: usize;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _40: usize;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+          scope 6 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:50: 8:56
+              debug self => _13;           // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _14;          // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _41: &usize;         // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _42: &usize;         // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _43: &usize;         // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _44: &usize;         // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug self => _41;       // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug other => _42;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug self => _43;       // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug other => _44;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _45: usize;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _46: usize;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+          scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:70: 8:76
+              debug self => _22;           // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _23;          // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _47: &usize;         // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _48: &usize;         // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _49: &usize;         // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _50: &usize;         // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug self => _47;       // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-                 debug other => _48;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug self => _49;       // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++                 debug other => _50;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _51: usize;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _52: usize;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+          _25 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+          _3 = &((*_25).0: usize);         // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+          StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+          _26 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+          _4 = &((*_26).1: usize);         // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+          StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+          _27 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+          _5 = &((*_27).2: usize);         // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+          StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+          _28 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+          _6 = &((*_28).3: usize);         // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+          StorageLive(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+          StorageLive(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:46
+          StorageLive(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41
+          _9 = &_3;                        // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41
+          StorageLive(_10);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          StorageLive(_11);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          _11 = _5;                        // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          _10 = &_11;                      // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+-         StorageLive(_29);                // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _31 = deref_copy (*_9);          // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _29 = _31;                       // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageLive(_30);                // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _32 = deref_copy (*_10);         // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _30 = _32;                       // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_33);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _33 = (*_29);                    // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _33 = (*_31);                    // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_34);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _34 = (*_30);                    // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _34 = (*_32);                    // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _8 = Le(move _33, move _34);     // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_34);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_33);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_30);                // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_29);                // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_11);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          StorageDead(_10);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          StorageDead(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+      }
+  
+      bb1: {
+          _0 = const true;                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+      }
+  
+      bb2: {
+          StorageLive(_16);                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+          StorageLive(_17);                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:66
+          StorageLive(_18);                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61
+          _18 = &_5;                       // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61
+          StorageLive(_19);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          StorageLive(_20);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          _20 = _3;                        // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          _19 = &_20;                      // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+-         StorageLive(_35);                // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _37 = deref_copy (*_18);         // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _35 = _37;                       // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageLive(_36);                // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _38 = deref_copy (*_19);         // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _36 = _38;                       // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_39);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _39 = (*_35);                    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _39 = (*_37);                    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_40);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _40 = (*_36);                    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _40 = (*_38);                    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _17 = Le(move _39, move _40);    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_40);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_39);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_36);                // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_35);                // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_20);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          StorageDead(_19);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          StorageDead(_18);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          switchInt(move _17) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+      }
+  
+      bb3: {
+          StorageDead(_16);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+-         StorageDead(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+-         StorageDead(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+-         StorageDead(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+-         StorageDead(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+          return;                          // scope 0 at $DIR/slice_filter.rs:+0:76: +0:76
+      }
+  
+      bb4: {
+          _7 = const false;                // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+          StorageDead(_12);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          goto -> bb2;                     // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+      }
+  
+      bb5: {
+          StorageLive(_12);                // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56
+          StorageLive(_13);                // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51
+          _13 = &_6;                       // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51
+          StorageLive(_14);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageLive(_15);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          _15 = _4;                        // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          _14 = &_15;                      // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+-         StorageLive(_41);                // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _43 = deref_copy (*_13);         // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _41 = _43;                       // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageLive(_42);                // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _44 = deref_copy (*_14);         // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _42 = _44;                       // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_45);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _45 = (*_41);                    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _45 = (*_43);                    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_46);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _46 = (*_42);                    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _46 = (*_44);                    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _12 = Le(move _45, move _46);    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_46);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_45);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_42);                // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_41);                // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_15);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_14);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_13);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          _7 = move _12;                   // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+          StorageDead(_12);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+      }
+  
+      bb6: {
+          _16 = const false;               // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+      }
+  
+      bb7: {
+          StorageLive(_21);                // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76
+          StorageLive(_22);                // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71
+          _22 = &_4;                       // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71
+          StorageLive(_23);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageLive(_24);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _24 = _6;                        // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _23 = &_24;                      // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+-         StorageLive(_47);                // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _49 = deref_copy (*_22);         // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _47 = _49;                       // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageLive(_48);                // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _50 = deref_copy (*_23);         // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _48 = _50;                       // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_51);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _51 = (*_47);                    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _51 = (*_49);                    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_52);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _52 = (*_48);                    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _52 = (*_50);                    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _21 = Le(move _51, move _52);    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_52);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_51);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_48);                // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         StorageDead(_47);                // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_24);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_23);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_22);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _16 = move _21;                  // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+      }
+  
+      bb8: {
+          StorageDead(_21);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_17);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _0 = move _16;                   // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+      }
+  }
+  
diff --git a/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff b/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff
new file mode 100644 (file)
index 0000000..259cd41
--- /dev/null
@@ -0,0 +1,241 @@
+- // MIR for `variant_a::{closure#0}` before DestinationPropagation
++ // MIR for `variant_a::{closure#0}` after DestinationPropagation
+  
+  fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:8:25: 8:39], _2: &&(usize, usize, usize, usize)) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/slice_filter.rs:+0:40: +0:40
+      let _3: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+      let _4: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+      let _5: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+      let _6: &usize;                      // in scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+      let mut _7: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:56
+      let mut _8: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:46
+      let mut _9: &&usize;                 // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:41
+      let mut _10: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46
+      let _11: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46
+      let mut _12: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:56
+      let mut _13: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:51
+      let mut _14: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56
+      let _15: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56
+      let mut _16: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:76
+      let mut _17: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:66
+      let mut _18: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:61
+      let mut _19: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66
+      let _20: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66
+      let mut _21: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:76
+      let mut _22: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:71
+      let mut _23: &&usize;                // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+      let _24: &usize;                     // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+      let mut _25: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      let mut _26: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      let mut _27: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      let mut _28: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+      scope 1 {
+          debug a => _3;                   // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28
+          debug b => _4;                   // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31
+          debug c => _5;                   // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34
+          debug d => _6;                   // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37
+          scope 2 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:40: 8:46
+              debug self => _9;            // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _10;          // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _29: &usize;         // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _30: &usize;         // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 3 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug self => _29;       // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug other => _30;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _31: usize;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _32: usize;      // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+          scope 4 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:60: 8:66
+              debug self => _18;           // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _19;          // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _33: &usize;         // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _34: &usize;         // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 5 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug self => _33;       // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug other => _34;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _35: usize;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _36: usize;      // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+          scope 6 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:50: 8:56
+              debug self => _13;           // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _14;          // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _37: &usize;         // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _38: &usize;         // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug self => _37;       // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug other => _38;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _39: usize;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _40: usize;      // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+          scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:70: 8:76
+              debug self => _22;           // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              debug other => _23;          // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _41: &usize;         // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              let mut _42: &usize;         // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug self => _41;       // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  debug other => _42;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _43: usize;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+                  let mut _44: usize;      // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+          _25 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+          _3 = &((*_25).0: usize);         // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+          StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+          _26 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+          _4 = &((*_26).1: usize);         // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+          StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+          _27 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+          _5 = &((*_27).2: usize);         // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+          StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+          _28 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+          _6 = &((*_28).3: usize);         // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+-         StorageLive(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+          StorageLive(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:46
+          StorageLive(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41
+          _9 = &_3;                        // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41
+          StorageLive(_10);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          StorageLive(_11);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          _11 = _5;                        // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          _10 = &_11;                      // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          _29 = deref_copy (*_9);          // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _30 = deref_copy (*_10);         // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_31);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _31 = (*_29);                    // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_32);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _32 = (*_30);                    // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _8 = Le(move _31, move _32);     // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_32);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_31);                // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_11);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          StorageDead(_10);                // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          StorageDead(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+          switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+      }
+  
+      bb1: {
+          _0 = const true;                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+      }
+  
+      bb2: {
+-         StorageLive(_16);                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+          StorageLive(_17);                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:66
+          StorageLive(_18);                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61
+          _18 = &_5;                       // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61
+          StorageLive(_19);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          StorageLive(_20);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          _20 = _3;                        // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          _19 = &_20;                      // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          _33 = deref_copy (*_18);         // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _34 = deref_copy (*_19);         // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_35);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _35 = (*_33);                    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_36);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _36 = (*_34);                    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _17 = Le(move _35, move _36);    // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_36);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_35);                // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_20);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          StorageDead(_19);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          StorageDead(_18);                // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+          switchInt(move _17) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+      }
+  
+      bb3: {
+-         StorageDead(_16);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+-         StorageDead(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          return;                          // scope 0 at $DIR/slice_filter.rs:+0:76: +0:76
+      }
+  
+      bb4: {
+-         StorageDead(_12);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          goto -> bb2;                     // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+      }
+  
+      bb5: {
+-         StorageLive(_12);                // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56
+          StorageLive(_13);                // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51
+          _13 = &_6;                       // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51
+          StorageLive(_14);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageLive(_15);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          _15 = _4;                        // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          _14 = &_15;                      // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          _37 = deref_copy (*_13);         // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _38 = deref_copy (*_14);         // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_39);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _39 = (*_37);                    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_40);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _40 = (*_38);                    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _12 = Le(move _39, move _40);    // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_40);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_39);                // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_15);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_14);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_13);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+-         _7 = move _12;                   // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+-         StorageDead(_12);                // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+-         switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
++         switchInt(move _12) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+      }
+  
+      bb6: {
+-         _16 = const false;               // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
++         _0 = const false;                // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+      }
+  
+      bb7: {
+-         StorageLive(_21);                // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76
+          StorageLive(_22);                // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71
+          _22 = &_4;                       // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71
+          StorageLive(_23);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageLive(_24);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _24 = _6;                        // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _23 = &_24;                      // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          _41 = deref_copy (*_22);         // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _42 = deref_copy (*_23);         // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_43);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _43 = (*_41);                    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageLive(_44);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          _44 = (*_42);                    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+-         _21 = Le(move _43, move _44);    // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++         _0 = Le(move _43, move _44);     // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_44);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_43);                // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+          StorageDead(_24);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_23);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_22);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+-         _16 = move _21;                  // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+      }
+  
+      bb8: {
+-         StorageDead(_21);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+          StorageDead(_17);                // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+-         _0 = move _16;                   // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+      }
+  }
+  
diff --git a/tests/mir-opt/slice_filter.variant_b-{closure#0}.CopyProp.diff b/tests/mir-opt/slice_filter.variant_b-{closure#0}.CopyProp.diff
new file mode 100644 (file)
index 0000000..c3b8e7d
--- /dev/null
@@ -0,0 +1,139 @@
+- // MIR for `variant_b::{closure#0}` before CopyProp
++ // MIR for `variant_b::{closure#0}` after CopyProp
+  
+  fn variant_b::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:12:25: 12:41], _2: &&(usize, usize, usize, usize)) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/slice_filter.rs:+0:42: +0:42
+      let _3: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+      let _4: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+      let _5: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+      let _6: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+      let mut _7: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:58
+      let mut _8: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:48
+      let mut _9: usize;                   // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:43
+      let mut _10: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:47: +0:48
+      let mut _11: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:58
+      let mut _12: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:53
+      let mut _13: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:57: +0:58
+      let mut _14: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:78
+      let mut _15: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:68
+      let mut _16: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:63
+      let mut _17: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:67: +0:68
+      let mut _18: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:78
+      let mut _19: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:73
+      let mut _20: usize;                  // in scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+      let mut _21: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      let mut _22: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      let mut _23: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      let mut _24: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      scope 1 {
+          debug a => _3;                   // in scope 1 at $DIR/slice_filter.rs:+0:29: +0:30
+          debug b => _4;                   // in scope 1 at $DIR/slice_filter.rs:+0:32: +0:33
+          debug c => _5;                   // in scope 1 at $DIR/slice_filter.rs:+0:35: +0:36
+          debug d => _6;                   // in scope 1 at $DIR/slice_filter.rs:+0:38: +0:39
+      }
+  
+      bb0: {
+          StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+          _21 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+          _3 = ((*_21).0: usize);          // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+          StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+          _22 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+          _4 = ((*_22).1: usize);          // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+          StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+          _23 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+          _5 = ((*_23).2: usize);          // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+          StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+          _24 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+          _6 = ((*_24).3: usize);          // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+          StorageLive(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+          StorageLive(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+-         StorageLive(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:43
+-         _9 = _3;                         // scope 1 at $DIR/slice_filter.rs:+0:42: +0:43
+-         StorageLive(_10);                // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48
+-         _10 = _5;                        // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48
+-         _8 = Le(move _9, move _10);      // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+-         StorageDead(_10);                // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48
+-         StorageDead(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48
++         _8 = Le(_3, _5);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+          switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+      }
+  
+      bb1: {
+          _0 = const true;                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+      }
+  
+      bb2: {
+          StorageLive(_14);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+          StorageLive(_15);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+-         StorageLive(_16);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:63
+-         _16 = _5;                        // scope 1 at $DIR/slice_filter.rs:+0:62: +0:63
+-         StorageLive(_17);                // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68
+-         _17 = _3;                        // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68
+-         _15 = Le(move _16, move _17);    // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+-         StorageDead(_17);                // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68
+-         StorageDead(_16);                // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68
++         _15 = Le(_5, _3);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+          switchInt(move _15) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+      }
+  
+      bb3: {
+          StorageDead(_14);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+          StorageDead(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+-         StorageDead(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+-         StorageDead(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+-         StorageDead(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+-         StorageDead(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+          return;                          // scope 0 at $DIR/slice_filter.rs:+0:78: +0:78
+      }
+  
+      bb4: {
+          _7 = const false;                // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+          StorageDead(_11);                // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          goto -> bb2;                     // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+      }
+  
+      bb5: {
+          StorageLive(_11);                // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+-         StorageLive(_12);                // scope 1 at $DIR/slice_filter.rs:+0:52: +0:53
+-         _12 = _6;                        // scope 1 at $DIR/slice_filter.rs:+0:52: +0:53
+-         StorageLive(_13);                // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+-         _13 = _4;                        // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+-         _11 = Le(move _12, move _13);    // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+-         StorageDead(_13);                // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+-         StorageDead(_12);                // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
++         _11 = Le(_6, _4);                // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+          _7 = move _11;                   // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+          StorageDead(_11);                // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+      }
+  
+      bb6: {
+          _14 = const false;               // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+      }
+  
+      bb7: {
+          StorageLive(_18);                // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+-         StorageLive(_19);                // scope 1 at $DIR/slice_filter.rs:+0:72: +0:73
+-         _19 = _4;                        // scope 1 at $DIR/slice_filter.rs:+0:72: +0:73
+-         StorageLive(_20);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+-         _20 = _6;                        // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+-         _18 = Le(move _19, move _20);    // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+-         StorageDead(_20);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+-         StorageDead(_19);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
++         _18 = Le(_4, _6);                // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+          _14 = move _18;                  // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+      }
+  
+      bb8: {
+          StorageDead(_18);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+          StorageDead(_15);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+          _0 = move _14;                   // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+      }
+  }
+  
diff --git a/tests/mir-opt/slice_filter.variant_b-{closure#0}.DestinationPropagation.diff b/tests/mir-opt/slice_filter.variant_b-{closure#0}.DestinationPropagation.diff
new file mode 100644 (file)
index 0000000..a43e84d
--- /dev/null
@@ -0,0 +1,113 @@
+- // MIR for `variant_b::{closure#0}` before DestinationPropagation
++ // MIR for `variant_b::{closure#0}` after DestinationPropagation
+  
+  fn variant_b::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:12:25: 12:41], _2: &&(usize, usize, usize, usize)) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/slice_filter.rs:+0:42: +0:42
+      let _3: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+      let _4: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+      let _5: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+      let _6: usize;                       // in scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+      let mut _7: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:58
+      let mut _8: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:48
+      let mut _9: bool;                    // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:58
+      let mut _10: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:78
+      let mut _11: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:68
+      let mut _12: bool;                   // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:78
+      let mut _13: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      let mut _14: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      let mut _15: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      let mut _16: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+      scope 1 {
+          debug a => _3;                   // in scope 1 at $DIR/slice_filter.rs:+0:29: +0:30
+          debug b => _4;                   // in scope 1 at $DIR/slice_filter.rs:+0:32: +0:33
+          debug c => _5;                   // in scope 1 at $DIR/slice_filter.rs:+0:35: +0:36
+          debug d => _6;                   // in scope 1 at $DIR/slice_filter.rs:+0:38: +0:39
+      }
+  
+      bb0: {
+          StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+          _13 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+          _3 = ((*_13).0: usize);          // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+          StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+          _14 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+          _4 = ((*_14).1: usize);          // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+          StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+          _15 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+          _5 = ((*_15).2: usize);          // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+          StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+          _16 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+          _6 = ((*_16).3: usize);          // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+-         StorageLive(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+          StorageLive(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+          _8 = Le(_3, _5);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+          switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+      }
+  
+      bb1: {
+          _0 = const true;                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+      }
+  
+      bb2: {
+-         StorageLive(_10);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+          StorageLive(_11);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+          _11 = Le(_5, _3);                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+          switchInt(move _11) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+      }
+  
+      bb3: {
+-         StorageDead(_10);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+-         StorageDead(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+          return;                          // scope 0 at $DIR/slice_filter.rs:+0:78: +0:78
+      }
+  
+      bb4: {
+-         StorageDead(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          goto -> bb2;                     // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+      }
+  
+      bb5: {
+-         StorageLive(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+          _9 = Le(_6, _4);                 // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+-         _7 = move _9;                    // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+-         StorageDead(_9);                 // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+          StorageDead(_8);                 // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+-         switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
++         switchInt(move _9) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+      }
+  
+      bb6: {
+-         _10 = const false;               // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
++         _0 = const false;                // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+      }
+  
+      bb7: {
+-         StorageLive(_12);                // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+-         _12 = Le(_4, _6);                // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+-         _10 = move _12;                  // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
++         _0 = Le(_4, _6);                 // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+          goto -> bb8;                     // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+      }
+  
+      bb8: {
+-         StorageDead(_12);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+          StorageDead(_11);                // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+-         _0 = move _10;                   // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
++         nop;                             // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+          goto -> bb3;                     // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+      }
+  }
+  
index b254bfeb7c992500212de9570d51fd6ae98b8dbc..7c67d2abcf7c37ccf1e0997d8550779a58c4d52f 100644 (file)
@@ -5,11 +5,11 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
     let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46
     let mut _2: std::ops::ControlFlow<E, T>; // in scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
     let mut _3: isize;                   // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:22
-    let mut _4: T;                       // in scope 0 at $DIR/try_identity_e2e.rs:+4:48: +4:49
-    let mut _5: E;                       // in scope 0 at $DIR/try_identity_e2e.rs:+5:46: +5:47
+    let _4: T;                           // in scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
+    let _5: E;                           // in scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
     let mut _6: isize;                   // in scope 0 at $DIR/try_identity_e2e.rs:+8:13: +8:37
     let _7: T;                           // in scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
-    let mut _8: E;                       // in scope 0 at $DIR/try_identity_e2e.rs:+9:49: +9:50
+    let _8: E;                           // in scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
     scope 1 {
         debug v => _4;                   // in scope 1 at $DIR/try_identity_e2e.rs:+4:20: +4:21
     }
@@ -30,6 +30,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb1: {
+        StorageLive(_5);                 // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
         _5 = move ((_1 as Err).0: E);    // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
         Deinit(_2);                      // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
         ((_2 as Break).0: E) = move _5;  // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
@@ -39,6 +40,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb2: {
+        StorageLive(_4);                 // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
         _4 = move ((_1 as Ok).0: T);     // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
         Deinit(_2);                      // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
         ((_2 as Continue).0: T) = move _4; // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
@@ -48,6 +50,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb3: {
+        StorageLive(_8);                 // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
         _8 = move ((_2 as Break).0: E);  // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
         Deinit(_0);                      // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
         ((_0 as Err).0: E) = move _8;    // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
@@ -61,6 +64,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb5: {
+        StorageLive(_7);                 // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
         _7 = move ((_2 as Continue).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
         Deinit(_0);                      // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
         ((_0 as Ok).0: T) = move _7;     // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
index cdbc0681cb8a363ae2acadeeb236c7718ad3c00a..4a838e140262e76e51434fcb2f51f5bf4a743ea1 100644 (file)
@@ -5,7 +5,7 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
     let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46
     let mut _2: isize;                   // in scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:18
     let _3: T;                           // in scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
-    let mut _4: E;                       // in scope 0 at $DIR/try_identity_e2e.rs:+4:34: +4:35
+    let _4: E;                           // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
     scope 1 {
         debug v => _3;                   // in scope 1 at $DIR/try_identity_e2e.rs:+3:16: +3:17
     }
@@ -19,6 +19,7 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb1: {
+        StorageLive(_4);                 // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
         _4 = move ((_1 as Err).0: E);    // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
         Deinit(_0);                      // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
         ((_0 as Err).0: E) = move _4;    // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
@@ -31,6 +32,7 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb3: {
+        StorageLive(_3);                 // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
         _3 = move ((_1 as Ok).0: T);     // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
         Deinit(_0);                      // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
         ((_0 as Ok).0: T) = move _3;     // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
index b95d91b13dd7976c646481fc8425b4754b874095..318119bd477c1572cb3e155597251d5723ffa9b8 100644 (file)
@@ -4,9 +4,7 @@ fn while_loop(_1: bool) -> () {
     debug c => _1;                       // in scope 0 at $DIR/while_storage.rs:+0:15: +0:16
     let mut _0: ();                      // return place in scope 0 at $DIR/while_storage.rs:+0:24: +0:24
     let mut _2: bool;                    // in scope 0 at $DIR/while_storage.rs:+1:11: +1:22
-    let mut _3: bool;                    // in scope 0 at $DIR/while_storage.rs:+1:20: +1:21
-    let mut _4: bool;                    // in scope 0 at $DIR/while_storage.rs:+2:12: +2:23
-    let mut _5: bool;                    // in scope 0 at $DIR/while_storage.rs:+2:21: +2:22
+    let mut _3: bool;                    // in scope 0 at $DIR/while_storage.rs:+2:12: +2:23
 
     bb0: {
         goto -> bb1;                     // scope 0 at $DIR/while_storage.rs:+1:5: +5:6
@@ -14,41 +12,35 @@ fn while_loop(_1: bool) -> () {
 
     bb1: {
         StorageLive(_2);                 // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
-        StorageLive(_3);                 // scope 0 at $DIR/while_storage.rs:+1:20: +1:21
-        _3 = _1;                         // scope 0 at $DIR/while_storage.rs:+1:20: +1:21
-        _2 = get_bool(move _3) -> bb2;   // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
+        _2 = get_bool(_1) -> bb2;        // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
                                          // mir::Constant
                                          // + span: $DIR/while_storage.rs:10:11: 10:19
                                          // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) }
     }
 
     bb2: {
-        StorageDead(_3);                 // scope 0 at $DIR/while_storage.rs:+1:21: +1:22
         switchInt(move _2) -> [0: bb7, otherwise: bb3]; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
     }
 
     bb3: {
-        StorageLive(_4);                 // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
-        StorageLive(_5);                 // scope 0 at $DIR/while_storage.rs:+2:21: +2:22
-        _5 = _1;                         // scope 0 at $DIR/while_storage.rs:+2:21: +2:22
-        _4 = get_bool(move _5) -> bb4;   // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
+        StorageLive(_3);                 // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
+        _3 = get_bool(_1) -> bb4;        // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
                                          // mir::Constant
                                          // + span: $DIR/while_storage.rs:11:12: 11:20
                                          // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) }
     }
 
     bb4: {
-        StorageDead(_5);                 // scope 0 at $DIR/while_storage.rs:+2:22: +2:23
-        switchInt(move _4) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
+        switchInt(move _3) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
     }
 
     bb5: {
-        StorageDead(_4);                 // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
+        StorageDead(_3);                 // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
         goto -> bb7;                     // scope 0 at no-location
     }
 
     bb6: {
-        StorageDead(_4);                 // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
+        StorageDead(_3);                 // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
         StorageDead(_2);                 // scope 0 at $DIR/while_storage.rs:+5:5: +5:6
         goto -> bb1;                     // scope 0 at $DIR/while_storage.rs:+1:5: +5:6
     }
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 7e1b6aeb31558c30da283cc004473e47c7e2bca3..5bb38fc02af91be94cf296b3c6358341d0b6eb23 100644 (file)
@@ -1,12 +1,12 @@
 #![feature(rustc_private)]
 
-extern crate rustc_interface;
 extern crate rustc_driver;
+extern crate rustc_interface;
 extern crate rustc_session;
 extern crate rustc_span;
 
-use rustc_session::config::{Input, Options, OutputType, OutputTypes};
 use rustc_interface::interface;
+use rustc_session::config::{Input, Options, OutputType, OutputTypes};
 use rustc_span::source_map::FileName;
 
 use std::path::PathBuf;
@@ -50,7 +50,6 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
         crate_cfg: Default::default(),
         crate_check_cfg: Default::default(),
         input,
-        input_path: None,
         output_file: Some(output),
         output_dir: None,
         file_loader: None,
@@ -64,9 +63,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
 
     interface::run_compiler(config, |compiler| {
         // This runs all the passes prior to linking, too.
-        let linker = compiler.enter(|queries| {
-            queries.linker()
-        });
+        let linker = compiler.enter(|queries| queries.linker());
         if let Ok(linker) = linker {
             linker.link();
         }
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`
index 7c78d7783e0b6dbe9e29c95f2c562299c7489c78..e8a1121bfcd975c1023de411450ab6f200e0bc40 100644 (file)
@@ -5,7 +5,12 @@ include ../../run-make-fulldeps/tools.mk
 
 # We're using the llvm-nm instead of the system nm to ensure it is compatible
 # with the LLVM bitcode generated by rustc.
+# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm.
+ifndef IS_WINDOWS
 NM = "$(LLVM_BIN_DIR)"/llvm-nm
+else
+NM = nm
+endif
 
 all: $(call NATIVE_STATICLIB,native-staticlib)
        # Build a staticlib and a rlib, the `native_func` symbol will be bundled into them
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 9e603f95835986a8a9a9641145e2a56b1ce0acf3..722a49b02cb3bc499d8da6512e3f7a1a7a91babb 100644 (file)
@@ -4,15 +4,19 @@
 
 include ../../run-make-fulldeps/tools.mk
 
+# We'd be using the llvm-objdump instead of the system objdump to ensure compatibility
+# with the LLVM bitcode generated by rustc but on Windows  piping/IO redirection under MSYS2 is wonky with llvm-objdump.
+OBJDUMP = objdump
+
 all:
        $(RUSTC) --crate-type dylib --crate-name raw_dylib_test lib.rs -C prefer-dynamic
        $(RUSTC) --crate-type dylib --crate-name raw_dylib_test_wrapper lib_wrapper.rs -C prefer-dynamic
        $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" -C prefer-dynamic
        # Make sure we don't find an import to the functions we expect to be inlined.
-       "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function"
-       "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline"
+       $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function"
+       $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline"
        # Make sure we do find an import to the functions we expect to be imported.
-       "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function"
+       $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function"
        $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
        $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
 ifdef IS_MSVC
index 4574cf17f0ef069454b85ead103384503dd7813c..37b8d809a27423d910c25532380894eeb53780d7 100644 (file)
@@ -6,7 +6,12 @@
 
 # We're using the llvm-nm instead of the system nm to ensure it is compatible
 # with the LLVM bitcode generated by rustc.
+# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm.
+ifndef IS_WINDOWS
 NM = "$(LLVM_BIN_DIR)"/llvm-nm
+else
+NM = nm
+endif
 
 all:
        # Build strange-named dep.
index 0b991ac42e3dc5a634e9848e670adc8be621583b..7fb6ce8d1e4110db9227c636f2e76a1b11a43eb4 100644 (file)
@@ -6,7 +6,12 @@
 
 # We're using the llvm-nm instead of the system nm to ensure it is compatible
 # with the LLVM bitcode generated by rustc.
+# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm.
+ifndef IS_WINDOWS
 NM = "$(LLVM_BIN_DIR)"/llvm-nm
+else
+NM = nm
+endif
 
 all: $(call NATIVE_STATICLIB,native_dep_1) $(call NATIVE_STATICLIB,native_dep_2) $(call NATIVE_STATICLIB,native_dep_3)
        $(RUSTC) rust_dep_up.rs --crate-type=rlib -Zpacked_bundled_libs
index 108cf8abcb529d2bf238733f3487c4430a053766..971c2f9480ea2fb00a6bb7f235af31d5865bec01 100644 (file)
@@ -1,3 +1,5 @@
+// Small test to ensure the "src-line-numbers" element is only present once on
+// the page.
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 click: ".srclink"
 wait-for: ".src-line-numbers"
index 94c1a6525aaa5e08bfbce9db7531c71cdcca5384..8561f537f3d32a8a18ce237832d04593fdf37be7 100644 (file)
@@ -9,16 +9,16 @@ size: (1080, 600)
 // Check that their content is inside <pre><code>
 assert-count: (".example-wrap pre > code", 4)
 // Check that function signature is inside <pre><code>
-assert: "pre.rust.fn > code"
+assert: ".item-decl pre.rust > code"
 
 goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
-assert: "pre.rust.struct > code"
+assert: ".item-decl pre.rust > code"
 
 goto: "file://" + |DOC_PATH| + "/test_docs/enum.AnEnum.html"
-assert: "pre.rust.enum > code"
+assert: ".item-decl pre.rust > code"
 
 goto: "file://" + |DOC_PATH| + "/test_docs/trait.AnotherOne.html"
-assert: "pre.rust.trait > code"
+assert: ".item-decl pre.rust > code"
 
 goto: "file://" + |DOC_PATH| + "/test_docs/type.SomeType.html"
-assert: "pre.rust.typedef > code"
+assert: ".item-decl pre.rust > code"
index 8ba005b0c35a0c7da4ee52ee7d72d91e05e4e9cb..fafb156317866cc1970c78c0cc1395a0485afdf2 100644 (file)
@@ -20,7 +20,7 @@ goto: "file://" + |DOC_PATH| + "/lib2/trait.Trait.html"
 // This is a complex selector, so here's how it works:
 //
 // * //*[@class='item-decl'] — selects element of any tag with classes docblock and item-decl
-// * /pre[@class='rust trait'] — selects immediate child with tag pre and classes rust and trait
+// * /pre[@class='rust'] — selects immediate child with tag pre and class rust
 // * /code — selects immediate child with tag code
 // * /a[@class='constant'] — selects immediate child with tag a and class constant
 // * //text() — selects child that is text node
@@ -29,11 +29,11 @@ goto: "file://" + |DOC_PATH| + "/lib2/trait.Trait.html"
 // This uses '/parent::*' as a proxy for the style of the text node.
 // We can't just select the '<a>' because intermediate tags could be added.
 assert-count: (
-    "//*[@class='item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*",
+    "//*[@class='item-decl']/pre[@class='rust']/code/a[@class='constant']//text()/parent::*",
     1,
 )
 assert-css: (
-    "//*[@class='item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*",
+    "//*[@class='item-decl']/pre[@class='rust']/code/a[@class='constant']//text()/parent::*",
     {"font-weight": "400"},
 )
 
index 05f8ddc716e8703b6bcadd675c04b83dbd6fc568..3f4f65890b422aa83e1e5f250e848886e4d74c12 100644 (file)
@@ -20,7 +20,7 @@ assert-css: (
 // table like view
 assert-css: (".item-right.docblock-short", { "padding-left": "0px" })
 compare-elements-position-near: (
-    "//*[@class='item-left module-item']//a[text()='replaced_function']",
+    "//*[@class='item-left']//a[text()='replaced_function']",
     ".item-left .stab.deprecated",
     {"y": 2},
 )
@@ -32,7 +32,7 @@ compare-elements-position: (
 
 // Ensure no wrap
 compare-elements-position: (
-    "//*[@class='item-left module-item']//a[text()='replaced_function']/..",
+    "//*[@class='item-left']//a[text()='replaced_function']/..",
     "//*[@class='item-right docblock-short'][text()='a thing with a label']",
     ("y"),
 )
@@ -43,7 +43,7 @@ size: (600, 600)
 // staggered layout with 2em spacing
 assert-css: (".item-right.docblock-short", { "padding-left": "32px" })
 compare-elements-position-near: (
-    "//*[@class='item-left module-item']//a[text()='replaced_function']",
+    "//*[@class='item-left']//a[text()='replaced_function']",
     ".item-left .stab.deprecated",
     {"y": 2},
 )
@@ -55,7 +55,7 @@ compare-elements-position: (
 
 // Ensure wrap
 compare-elements-position-false: (
-    "//*[@class='item-left module-item']//a[text()='replaced_function']/..",
+    "//*[@class='item-left']//a[text()='replaced_function']/..",
     "//*[@class='item-right docblock-short'][text()='a thing with a label']",
     ("y"),
 )
index 3423a449de478a38b5dafe8ab921d0e69102801d..c527cfbfcbc5630558ab81e40d3fd7c0d094d109 100644 (file)
@@ -1,4 +1,4 @@
 // This test checks that code blocks in list are supported.
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 goto: "./fn.check_list_code_block.html"
-assert: ("pre.rust.fn")
+assert: (".item-decl pre.rust")
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 cd3676a9871385703857de8edc0061c351a8a96f..5940962a8ddba7a338234d3789c079e5987dc32e 100644 (file)
@@ -1,7 +1,7 @@
 // This test checks that the correct font is used on module items (in index.html pages).
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 assert-css: (
-    ".item-table .module-item a",
+    ".item-table .item-left > a",
     {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
     ALL,
 )
index 10651a3f6696d5ef41eaef999ee37c527446b97a..1b5c3a0d202a0cfd1bd88fb96cb528764ff69822 100644 (file)
@@ -1,3 +1,5 @@
+// This test ensures that the scraped examples buttons are working as expecting
+// when 'Enter' key is pressed when they're focused.
 goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html"
 
 // The next/prev buttons vertically scroll the code viewport between examples
index 40f31b2771b258f4d995510d45fc40836c4b2262..67c58826efc2691e226365fe3a4b9a0253af9353 100644 (file)
@@ -58,3 +58,39 @@ call-function: ("check-colors", {
     "help_hover_border": "rgb(0, 0, 0)",
     "help_hover_color": "rgb(0, 0, 0)",
 })
+
+// Now testing the top and bottom background in case there is only one scraped examples.
+goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html"
+
+define-function: (
+    "check-background",
+    (theme, background_color_start, background_color_end),
+    block {
+        local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", }
+        reload:
+        assert-css: (".scraped-example:not(.expanded) .code-wrapper::before", {
+            "background-image": "linear-gradient(" + |background_color_start| + ", " +
+                |background_color_end| + ")",
+        })
+        assert-css: (".scraped-example:not(.expanded) .code-wrapper::after", {
+            "background-image": "linear-gradient(to top, " + |background_color_start| + ", " +
+                |background_color_end| + ")",
+        })
+    },
+)
+
+call-function: ("check-background", {
+    "theme": "ayu",
+    "background_color_start": "rgb(15, 20, 25)",
+    "background_color_end": "rgba(15, 20, 25, 0)",
+})
+call-function: ("check-background", {
+    "theme": "dark",
+    "background_color_start": "rgb(53, 53, 53)",
+    "background_color_end": "rgba(53, 53, 53, 0)",
+})
+call-function: ("check-background", {
+    "theme": "light",
+    "background_color_start": "rgb(255, 255, 255)",
+    "background_color_end": "rgba(255, 255, 255, 0)",
+})
index f236dc3e0fe7681344504d8677b693de6c59044b..a84172885780856b3927b12a212ceb2666f9da68 100644 (file)
@@ -8,6 +8,10 @@ assert-false: "#settings"
 click: "#settings-menu"
 wait-for: "#settings"
 assert-css: ("#settings", {"display": "block"})
+
+// Store the line margin to compare with the settings.html later.
+store-css: (setting_line_margin, ".setting-line", "margin")
+
 // Let's close it by clicking on the same button.
 click: "#settings-menu"
 wait-for-css: ("#settings", {"display": "none"})
@@ -39,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"
@@ -105,6 +109,33 @@ assert-css: (
         "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
     },
 )
+// Now we check the setting-radio-name is on a different line than the label.
+compare-elements-position-near: (
+    "#theme .setting-radio-name",
+    "#theme .setting-radio-choices",
+    {"x": 1}
+)
+compare-elements-position-near-false: (
+    "#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 .setting-radio-choices #theme-light",
+    "#theme .setting-radio-choices #theme-dark",
+    {"y": 1}
+)
+compare-elements-position-near: (
+    "#theme .setting-radio-choices #theme-dark",
+    "#theme .setting-radio-choices #theme-ayu",
+    {"y": 1}
+)
+compare-elements-position-near: (
+    "#theme .setting-radio-choices #theme-ayu",
+    "#theme .setting-radio-choices #theme-system-preference",
+    {"y": 1}
+)
 
 // First we check the "default" display for toggles.
 assert-css: (
@@ -149,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.
@@ -169,13 +200,32 @@ 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: "?"
 wait-for-css: ("#help-button .popover", {"display": "block"})
 assert-css: ("#settings-menu .popover", {"display": "none"})
 
+// Now switch back to the settings popover, and make sure the keyboard
+// shortcut works when a check box is selected.
+click: "#settings-menu > a"
+wait-for-css: ("#settings-menu .popover", {"display": "block"})
+focus: "#auto-hide-large-items"
+press-key: "?"
+wait-for-css: ("#settings-menu .popover", {"display": "none"})
+wait-for-css: ("#help-button .popover", {"display": "block"})
+
+// Now switch back to the settings popover, and make sure the keyboard
+// shortcut works when a check box is selected.
+click: "#settings-menu > a"
+wait-for-css: ("#settings-menu .popover", {"display": "block"})
+wait-for-css: ("#help-button .popover", {"display": "none"})
+focus: "#theme-system-preference"
+press-key: "?"
+wait-for-css: ("#settings-menu .popover", {"display": "none"})
+wait-for-css: ("#help-button .popover", {"display": "block"})
+
 // Now we go to the settings page to check that the CSS is loaded as expected.
 goto: "file://" + |DOC_PATH| + "/settings.html"
 wait-for: "#settings"
@@ -184,6 +234,9 @@ assert-css: (".setting-line", {"position": "relative"})
 assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
 compare-elements-position: (".sub form", "#settings", ("x"))
 
+// Check that setting-line has the same margin in this mode as in the popover.
+assert-css: (".setting-line", {"margin": |setting_line_margin|})
+
 // We now check the display with JS disabled.
 assert-false: "noscript section"
 javascript: false
index 9233f37444b6ed9bd2846854b4b64afcc39e32bf..bab66dae70c4f02db9182a6656fdfd7f25881634 100644 (file)
@@ -4,13 +4,13 @@
 goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
 show-text: true
 // Check the impl headers.
-assert-css: (".impl.has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
-assert-css: (".impl.has-srclink .code-header", {"font-size": "18px", "font-weight": 600}, ALL)
+assert-css: (".impl .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
+assert-css: (".impl .code-header", {"font-size": "18px", "font-weight": 600}, ALL)
 // Check the impl items.
-assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
-assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px", "font-weight": 600}, ALL)
+assert-css: (".impl-items .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
+assert-css: (".impl-items .code-header", {"font-size": "16px", "font-weight": 600}, ALL)
 
 // Check that we can click on source link
 store-document-property: (url, "URL")
-click: ".impl-items .has-srclink .srclink"
+click: ".impl-items .srclink"
 assert-document-property-false: {"URL": |url|}
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 d3a672ddde6e491250e4022c1c7a1a5ee3be4bbc..3ecb25c82a44e133aa44209904eb871967590478 100644 (file)
@@ -4,8 +4,8 @@ goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 show-text: true
 
 compare-elements-property: (
-    "//a[@title='test_docs::safe_fn fn']/..",
-    "//a[@title='test_docs::unsafe_fn fn']/..",
+    "//a[@title='fn test_docs::safe_fn']/..",
+    "//a[@title='fn test_docs::unsafe_fn']/..",
     ["clientHeight"]
 )
 
index 858046e72e9a456518acb9d749bd972218101a00..1b4c7b40570203b2b4eecb55488615984a72505d 100644 (file)
@@ -3,8 +3,8 @@ const QUERY = 'macro:print';
 const EXPECTED = {
     'others': [
         { 'path': 'std', 'name': 'print' },
-        { 'path': 'std', 'name': 'eprint' },
         { 'path': 'std', 'name': 'println' },
+        { 'path': 'std', 'name': 'eprint' },
         { 'path': 'std', 'name': 'eprintln' },
     ],
 };
index 25efbad26954003233d959692152f34888221bd7..fd5c5489d79cfe04a4d844cfdec619ec542719f7 100644 (file)
@@ -6,8 +6,8 @@ const FILTER_CRATE = 'std';
 const EXPECTED = {
     'others': [
         { 'path': 'std', 'name': 'print' },
-        { 'path': 'std', 'name': 'eprint' },
         { 'path': 'std', 'name': 'println' },
+        { 'path': 'std', 'name': 'eprint' },
         { 'path': 'std', 'name': 'eprintln' },
         { 'path': 'std::pin', 'name': 'pin' },
         { 'path': 'std::future', 'name': 'join' },
index cd0e8e7b4a9eb41524adbb55fc8d9c931a8d20d4..fc44a566af21f8ab1f2d9554370366c60975ab09 100644 (file)
@@ -3,7 +3,8 @@ const QUERY = 'Vec::new';
 const EXPECTED = {
     'others': [
         { 'path': 'std::vec::Vec', 'name': 'new' },
-        { 'path': 'std::vec::Vec', 'name': 'ne' },
-        { 'path': 'alloc::vec::Vec', 'name': 'ne' },
+        { 'path': 'alloc::vec::Vec', 'name': 'new' },
+        { 'path': 'std::vec::Vec', 'name': 'new_in' },
+        { 'path': 'alloc::vec::Vec', 'name': 'new_in' },
     ],
 };
index d14672af71fd6b714d3107b68c04ee16bd130d71..3b2f15a40bf87448fb9f441266e1934d1a6c6301 100644 (file)
@@ -4,7 +4,6 @@ const EXPECTED = {
     'others': [
         { 'path': 'search_short_types', 'name': 'P' },
         { 'path': 'search_short_types::VeryLongTypeName', 'name': 'p' },
-        { 'path': 'search_short_types', 'name': 'Ap' },
-        { 'path': 'search_short_types::VeryLongTypeName', 'name': 'ap' },
+        { 'path': 'search_short_types', 'name': 'Pa' },
     ],
 };
index 939da186fbcdb2dcac7b1f6b7f5dca4d7c280f32..4b1e04234c870594bcaaf458bb9b2fbe39507c8c 100644 (file)
@@ -1,10 +1,12 @@
+// check-pass
 // normalize-stderr-test: "`.*`" -> "`DEF_ID`"
 // normalize-stdout-test: "`.*`" -> "`DEF_ID`"
 // edition:2018
 
 pub async fn f() -> impl std::fmt::Debug {
+    // rustdoc doesn't care that this is infinitely sized
     #[derive(Debug)]
-    enum E { //~ ERROR
+    enum E {
         This(E),
         Unit,
     }
diff --git a/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr b/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr
deleted file mode 100644 (file)
index aff7402..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0072]: recursive type `DEF_ID` has infinite size
-  --> $DIR/infinite-recursive-type-impl-trait-return.rs:7:5
-   |
-LL |     enum E {
-   |     ^^^^^^
-LL |         This(E),
-   |              - recursive without indirection
-   |
-help: insert some indirection (e.g., a `DEF_ID`) to break the cycle
-   |
-LL |         This(Box<E>),
-   |              ++++ +
-
-error: aborting due to previous error
-
-For more information about this error, try `DEF_ID`.
index ac51725749867cea7f7b979839320140378480d3..ac79582fb3f0df48e75c11cc1101e0d9f99ac5bc 100644 (file)
@@ -1,5 +1,8 @@
+// check-pass
+
 fn f() -> impl Sized {
-    enum E { //~ ERROR
+    // rustdoc doesn't care that this is infinitely sized
+    enum E {
         V(E),
     }
     unimplemented!()
diff --git a/tests/rustdoc-ui/infinite-recursive-type-impl-trait.stderr b/tests/rustdoc-ui/infinite-recursive-type-impl-trait.stderr
deleted file mode 100644 (file)
index a61577b..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0072]: recursive type `f::E` has infinite size
-  --> $DIR/infinite-recursive-type-impl-trait.rs:2:5
-   |
-LL |     enum E {
-   |     ^^^^^^
-LL |         V(E),
-   |           - recursive without indirection
-   |
-help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
-   |
-LL |         V(Box<E>),
-   |           ++++ +
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0072`.
index 597d19e748cb7a1836ec4e8f2f961d0b08b02ee4..6140a06c555f2c5641c68b9a40a911225b3a6be6 100644 (file)
@@ -77,8 +77,6 @@ LL | ///     ```
    |         ^^^
    |
    = note: error from rustc: unknown start of token: `
-   = note: error from rustc: unknown start of token: `
-   = note: error from rustc: unknown start of token: `
 
 warning: could not parse code block as Rust code
   --> $DIR/invalid-syntax.rs:64:5
index 4bdecdc1b79446302261626e67df86d9c77e6ad0..4f07fca82d1ebfb860461506cf7ba25986b0d7a2 100644 (file)
@@ -20,6 +20,7 @@
     -Z                                 dlltool=val -- import library generation tool (windows-gnu only)
     -Z                 dont-buffer-diagnostics=val -- emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) (default: no)
     -Z                           drop-tracking=val -- enables drop tracking in generators (default: no)
+    -Z                       drop-tracking-mir=val -- enables drop tracking on MIR in generators (default: no)
     -Z                        dual-proc-macros=val -- load proc macros for both target and host, but only link to the target (default: no)
     -Z                          dump-dep-graph=val -- dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) (default: no)
     -Z                  dump-drop-tracking-cfg=val -- dump drop-tracking control-flow graph as a `.dot` file (default: no)
     -Z                                 threads=val -- use a thread pool with N threads
     -Z                        time-llvm-passes=val -- measure time of each LLVM pass (default: no)
     -Z                             time-passes=val -- measure time of each rustc pass (default: no)
+    -Z                   tiny-const-eval-limit=val -- sets a tiny, non-configurable limit for const eval; useful for compiler tests
     -Z                               tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
     -Z                            trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
     -Z                       track-diagnostics=val -- tracks where in rustc a diagnostic was emitted
index 75e67330a3ebfe06bfa08bc45a1d64f4766c9bfd..a8587829d3ee7df8877c13ea57f157fbc12e7aff 100644 (file)
@@ -1 +1 @@
-<section id="associatedconstant.YOLO" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#16">source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
+<section id="associatedconstant.YOLO" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#16">source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
index c002519760242a4ce4d216f3918c1735d8e725cd..4c5e45fea2de599539014cb386bab21b9d4f02a2 100644 (file)
@@ -1 +1 @@
-<section id="associatedconstant.X" class="associatedconstant has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#42">source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
\ No newline at end of file
+<section id="associatedconstant.X" class="associatedconstant"><a class="srclink rightside" href="../src/foo/anchors.rs.html#42">source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
\ No newline at end of file
index b9ec8bf4c09a023c0142f3d3b5fa88cbcf511aa7..44957a5b71a54c333e091d349269feda1099577e 100644 (file)
@@ -1 +1 @@
-<section id="method.new" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#48">source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -&gt; Self</h4></section>
\ No newline at end of file
+<section id="method.new" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#48">source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -&gt; Self</h4></section>
\ No newline at end of file
index 4308ddad412069e86acea1890b91f62032668536..75c2caf87a89fbf4540b6accb5b7e9a5adec2716 100644 (file)
@@ -1 +1 @@
-<section id="method.bar" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#23">source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section>
\ No newline at end of file
+<section id="method.bar" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#23">source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section>
\ No newline at end of file
index 91eed8a3742926f223e38ebefac3af3160712e9c..38575eadfa9698802e3bd842f56cb163d67b3e01 100644 (file)
@@ -1 +1 @@
-<section id="tymethod.foo" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#20">source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section>
\ No newline at end of file
+<section id="tymethod.foo" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#20">source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section>
\ No newline at end of file
index 2c66d5aa315abab54a6f140ee77f4b861a452531..dd65d98fee69e96102cbd824c8329c232bc57de6 100644 (file)
@@ -1 +1 @@
-<section id="associatedtype.T" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#13">source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section>
\ No newline at end of file
+<section id="associatedtype.T" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#13">source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section>
\ No newline at end of file
index 72a1186bf7e301853072bcc0ec84267971911fba..f8b59160f15ee07d3a3373a28f7616ccf1ee8dd9 100644 (file)
@@ -1 +1 @@
-<section id="associatedtype.Y" class="associatedtype has-srclink"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
+<section id="associatedtype.Y" class="associatedtype"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
index 07f92ac51b9f53de511b434344791a001f42fd37..e7c0ee2de1a7a9036cc55a6ea9f6aecd588acfd5 100644 (file)
@@ -4,25 +4,25 @@
 pub struct MyBox<T: ?Sized>(*const T);
 
 // @has 'foo/fn.alpha.html'
-// @snapshot link_slice_u32 - '//pre[@class="rust fn"]/code'
+// @snapshot link_slice_u32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn alpha() -> &'static [u32; 1] {
     loop {}
 }
 
 // @has 'foo/fn.beta.html'
-// @snapshot link_slice_generic - '//pre[@class="rust fn"]/code'
+// @snapshot link_slice_generic - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn beta<T>() -> &'static [T; 1] {
     loop {}
 }
 
 // @has 'foo/fn.gamma.html'
-// @snapshot link_box_u32 - '//pre[@class="rust fn"]/code'
+// @snapshot link_box_u32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn gamma() -> MyBox<[u32; 1]> {
     loop {}
 }
 
 // @has 'foo/fn.delta.html'
-// @snapshot link_box_generic - '//pre[@class="rust fn"]/code'
+// @snapshot link_box_generic - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn delta<T>() -> MyBox<[T; 1]> {
     loop {}
 }
index 3da19a13e5331ecb3e83dabc2b014f252eb98a01..77b139b644f3a8dd97b0cff39336735535d6c22e 100644 (file)
@@ -1,5 +1,5 @@
 pub trait Foo {
-    // @has assoc_consts/trait.Foo.html '//*[@class="rust trait"]' \
+    // @has assoc_consts/trait.Foo.html '//div[@class="item-decl"]/pre[@class="rust"]' \
     //      'const FOO: usize = 13usize;'
     // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
     const FOO: usize = 12 + 1;
index a409d64131afdfa96de35c418376f41569be6738..ab9702a24f469834a8fba8881cd660977831b744 100644 (file)
@@ -10,5 +10,5 @@ pub trait AsExpression<T> {
 }
 
 // @has foo/type.AsExprOf.html
-// @has - '//pre[@class="rust typedef"]' 'type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;'
 pub type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;
index a9e5b8d0019280842bd4a0d4e82623a1665ae524..de36c8ffeff0f6121e63f6ef38a24efb28d4ed8b 100644 (file)
@@ -12,8 +12,8 @@ pub trait Index<I: ?Sized> {
 }
 
 // @has assoc_types/fn.use_output.html
-// @has - '//*[@class="rust fn"]' '-> &T::Output'
-// @has - '//*[@class="rust fn"]//a[@href="trait.Index.html#associatedtype.Output"]' 'Output'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' '-> &T::Output'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]//a[@href="trait.Index.html#associatedtype.Output"]' 'Output'
 pub fn use_output<T: Index<usize>>(obj: &T, index: usize) -> &T::Output {
     obj.index(index)
 }
@@ -23,13 +23,13 @@ pub trait Feed {
 }
 
 // @has assoc_types/fn.use_input.html
-// @has - '//*[@class="rust fn"]' 'T::Input'
-// @has - '//*[@class="rust fn"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'T::Input'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
 pub fn use_input<T: Feed>(_feed: &T, _element: T::Input) { }
 
 // @has assoc_types/fn.cmp_input.html
-// @has - '//*[@class="rust fn"]' 'where T::Input: PartialEq<U::Input>'
-// @has - '//*[@class="rust fn"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where T::Input: PartialEq<U::Input>'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
 pub fn cmp_input<T: Feed, U: Feed>(a: &T::Input, b: &U::Input) -> bool
     where T::Input: PartialEq<U::Input>
 {
index af765c51ace391da7ea7608e5d85b46f9d9939af..8cafb5a2497a385acfaa94d5e757bc970b28d443 100644 (file)
@@ -1,35 +1,35 @@
 // edition:2018
-// @has async_fn/fn.foo.html '//pre[@class="rust fn"]' 'pub async fn foo() -> Option<Foo>'
+// @has async_fn/fn.foo.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn foo() -> Option<Foo>'
 pub async fn foo() -> Option<Foo> {
     None
 }
 
-// @has async_fn/fn.bar.html '//pre[@class="rust fn"]' 'pub async fn bar(a: i32, b: i32) -> i32'
+// @has async_fn/fn.bar.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn bar(a: i32, b: i32) -> i32'
 pub async fn bar(a: i32, b: i32) -> i32 {
     0
 }
 
-// @has async_fn/fn.baz.html '//pre[@class="rust fn"]' 'pub async fn baz<T>(a: T) -> T'
+// @has async_fn/fn.baz.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn baz<T>(a: T) -> T'
 pub async fn baz<T>(a: T) -> T {
     a
 }
 
-// @has async_fn/fn.qux.html '//pre[@class="rust fn"]' 'pub async unsafe fn qux() -> char'
+// @has async_fn/fn.qux.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async unsafe fn qux() -> char'
 pub async unsafe fn qux() -> char {
     '⚠'
 }
 
-// @has async_fn/fn.mut_args.html '//pre[@class="rust fn"]' 'pub async fn mut_args(a: usize)'
+// @has async_fn/fn.mut_args.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn mut_args(a: usize)'
 pub async fn mut_args(mut a: usize) {}
 
-// @has async_fn/fn.mut_ref.html '//pre[@class="rust fn"]' 'pub async fn mut_ref(x: i32)'
+// @has async_fn/fn.mut_ref.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn mut_ref(x: i32)'
 pub async fn mut_ref(ref mut x: i32) {}
 
 trait Bar {}
 
 impl Bar for () {}
 
-// @has async_fn/fn.quux.html '//pre[@class="rust fn"]' 'pub async fn quux() -> impl Bar'
+// @has async_fn/fn.quux.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn quux() -> impl Bar'
 pub async fn quux() -> impl Bar {
     ()
 }
@@ -50,46 +50,46 @@ pub trait Pattern<'a> {}
 
 pub trait Trait<const N: usize> {}
 // @has async_fn/fn.const_generics.html
-// @has - '//pre[@class="rust fn"]' 'pub async fn const_generics<const N: usize>(_: impl Trait<N>)'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn const_generics<const N: usize>(_: impl Trait<N>)'
 pub async fn const_generics<const N: usize>(_: impl Trait<N>) {}
 
 // test that elided lifetimes are properly elided and not displayed as `'_`
 // regression test for #63037
 // @has async_fn/fn.elided.html
-// @has - '//pre[@class="rust fn"]' 'pub async fn elided(foo: &str) -> &str'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn elided(foo: &str) -> &str'
 pub async fn elided(foo: &str) -> &str {}
 // This should really be shown as written, but for implementation reasons it's difficult.
 // See `impl Clean for TyKind::Ref`.
 // @has async_fn/fn.user_elided.html
-// @has - '//pre[@class="rust fn"]' 'pub async fn user_elided(foo: &str) -> &str'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn user_elided(foo: &str) -> &str'
 pub async fn user_elided(foo: &'_ str) -> &str {}
 // @has async_fn/fn.static_trait.html
-// @has - '//pre[@class="rust fn"]' 'pub async fn static_trait(foo: &str) -> Box<dyn Bar>'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn static_trait(foo: &str) -> Box<dyn Bar>'
 pub async fn static_trait(foo: &str) -> Box<dyn Bar> {}
 // @has async_fn/fn.lifetime_for_trait.html
-// @has - '//pre[@class="rust fn"]' "pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_>"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_>"
 pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_> {}
 // @has async_fn/fn.elided_in_input_trait.html
-// @has - '//pre[@class="rust fn"]' "pub async fn elided_in_input_trait(t: impl Pattern<'_>)"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn elided_in_input_trait(t: impl Pattern<'_>)"
 pub async fn elided_in_input_trait(t: impl Pattern<'_>) {}
 
 struct AsyncFdReadyGuard<'a, T> { x: &'a T }
 
 impl Foo {
     // @has async_fn/struct.Foo.html
-    // @has - '//*[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+    // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
     pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
     // taken from `tokio` as an example of a method that was particularly bad before
-    // @has - '//*[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
+    // @has - '//*[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
     pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
-    // @has - '//*[@class="method has-srclink"]' "pub async fn mut_self(&mut self)"
+    // @has - '//*[@class="method"]' "pub async fn mut_self(&mut self)"
     pub async fn mut_self(&mut self) {}
 }
 
 // test named lifetimes, just in case
 // @has async_fn/fn.named.html
-// @has - '//pre[@class="rust fn"]' "pub async fn named<'a, 'b>(foo: &'a str) -> &'b str"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn named<'a, 'b>(foo: &'a str) -> &'b str"
 pub async fn named<'a, 'b>(foo: &'a str) -> &'b str {}
 // @has async_fn/fn.named_trait.html
-// @has - '//pre[@class="rust fn"]' "pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b>"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b>"
 pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b> {}
index a36dadced87d71e906c79babf398039265b46c12..70e2e5c29508c211b28246df05e984b8fc2167b4 100644 (file)
@@ -1,13 +1,13 @@
 #![crate_name = "foo"]
 
-// @has foo/fn.f.html '//*[@class="rust fn"]' '#[no_mangle]'
+// @has foo/fn.f.html '//div[@class="item-decl"]/pre[@class="rust"]' '#[no_mangle]'
 #[no_mangle]
 pub extern "C" fn f() {}
 
-// @has foo/fn.g.html '//*[@class="rust fn"]' '#[export_name = "bar"]'
+// @has foo/fn.g.html '//div[@class="item-decl"]/pre[@class="rust"]' '#[export_name = "bar"]'
 #[export_name = "bar"]
 pub extern "C" fn g() {}
 
-// @has foo/struct.Repr.html '//*[@class="item-decl"]' '#[repr(C, align(8))]'
+// @has foo/struct.Repr.html '//div[@class="item-decl"]' '#[repr(C, align(8))]'
 #[repr(C, align(8))]
 pub struct Repr;
index 45664dfc3823da490d5625df87efdb3c2594b43e..5143968bbd4390df0bab4c66cb4eb1f611eeb7c6 100644 (file)
@@ -1,5 +1,5 @@
 // @has issue_85454/trait.FromResidual.html
-// @has - '//pre[@class="rust trait"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
 pub trait FromResidual<R = <Self as Try>::Residual> {
     fn from_residual(residual: R) -> Self;
 }
index addb6709db1da8a25fe823eda5029fa7a057e8d5..89c7f0a6f342c4814379c6c18ba4e270c15b0ef1 100644 (file)
@@ -5,8 +5,8 @@
 #![no_core]
 
 // @has 'foo/index.html'
-// @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'foobar'
-// @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'bar'
+// @has - '//*[@class="item-left"]/*[@class="stab portability"]' 'foobar'
+// @has - '//*[@class="item-left"]/*[@class="stab portability"]' 'bar'
 
 #[doc(cfg(feature = "foobar"))]
 mod imp_priv {
index 28eba849ace072df369e2abdccd1556b1da4fec9..18863abaeaccd3dd70c10c493639126b677f5848 100644 (file)
@@ -1,14 +1,14 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.bar.html
-// @has - '//*[@class="rust fn"]' 'pub const fn bar() -> '
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub const fn bar() -> '
 /// foo
 pub const fn bar() -> usize {
     2
 }
 
 // @has foo/struct.Foo.html
-// @has - '//*[@class="method has-srclink"]' 'const fn new()'
+// @has - '//*[@class="method"]' 'const fn new()'
 pub struct Foo(usize);
 
 impl Foo {
index 6cbae9abebb73021d2f43d5ee852a92336e128f0..b5226ad3f78bd6e0199ce2a4629b2207e406fbfa 100644 (file)
@@ -2,7 +2,7 @@
 
 use std::ops::Add;
 
-// @has foo/struct.Simd.html '//pre[@class="rust struct"]' 'pub struct Simd<T, const WIDTH: usize>'
+// @has foo/struct.Simd.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct Simd<T, const WIDTH: usize>'
 pub struct Simd<T, const WIDTH: usize> {
     inner: T,
 }
index 2693d9b596993ff1e75a5e411fbbecb2c0330a79..acc3b853e5679c577696ffb87ff3578e00791293 100644 (file)
@@ -1,5 +1,5 @@
 #![crate_name = "foo"]
 
-// @has foo/struct.Foo.html '//pre[@class="rust struct"]' \
+// @has foo/struct.Foo.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(_);'
 pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(T);
index 4279de91f56c1420bab481156484d54cdd9fe939..80a9ab3f12e881e708cdb480f5fe6f8ed8c4a0e3 100644 (file)
@@ -5,7 +5,7 @@ pub trait Array {
 }
 
 // @has foo/trait.Array.html
-// @has - '//*[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]'
+// @has - '//*[@class="impl"]' 'impl<T, const N: usize> Array for [T; N]'
 impl<T, const N: usize> Array for [T; N] {
     type Item = T;
 }
index 5bf76e3c4690818b361e7bfa8e2665e0b1c7ee11..543332d2c320b8922d18135ee7e27cfe01d25606 100644 (file)
@@ -3,21 +3,21 @@
 #![crate_name = "foo"]
 
 extern crate extern_crate;
-// @has foo/fn.extern_fn.html '//pre[@class="rust fn"]' \
+// @has foo/fn.extern_fn.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub fn extern_fn<const N: usize>() -> impl Iterator<Item = [u8; N]>'
 pub use extern_crate::extern_fn;
-// @has foo/struct.ExternTy.html '//pre[@class="rust struct"]' \
+// @has foo/struct.ExternTy.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub struct ExternTy<const N: usize> {'
 pub use extern_crate::ExternTy;
-// @has foo/type.TyAlias.html '//pre[@class="rust typedef"]' \
+// @has foo/type.TyAlias.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'type TyAlias<const N: usize> = ExternTy<N>;'
 pub use extern_crate::TyAlias;
-// @has foo/trait.WTrait.html '//pre[@class="rust trait"]' \
+// @has foo/trait.WTrait.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub trait WTrait<const N: usize, const M: usize>'
-// @has - '//*[@class="rust trait"]' 'fn hey<const P: usize>() -> usize'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn hey<const P: usize>() -> usize'
 pub use extern_crate::WTrait;
 
-// @has foo/trait.Trait.html '//pre[@class="rust trait"]' \
+// @has foo/trait.Trait.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub trait Trait<const N: usize>'
 // @has - '//*[@id="impl-Trait%3C1%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<1> for u8'
 // @has - '//*[@id="impl-Trait%3C2%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<2> for u8'
@@ -30,10 +30,10 @@ impl Trait<2> for u8 {}
 impl Trait<{1 + 2}> for u8 {}
 impl<const N: usize> Trait<N> for [u8; N] {}
 
-// @has foo/struct.Foo.html '//pre[@class="rust struct"]' \
+// @has foo/struct.Foo.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub struct Foo<const N: usize>where u8: Trait<N>'
 pub struct Foo<const N: usize> where u8: Trait<N>;
-// @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)'
+// @has foo/struct.Bar.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct Bar<T, const N: usize>(_)'
 pub struct Bar<T, const N: usize>([T; N]);
 
 // @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header"]' 'impl<const M: usize> Foo<M>where u8: Trait<M>'
@@ -56,32 +56,32 @@ pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N> {
     }
 }
 
-// @has foo/fn.test.html '//pre[@class="rust fn"]' \
+// @has foo/fn.test.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub fn test<const N: usize>() -> impl Trait<N>where u8: Trait<N>'
 pub fn test<const N: usize>() -> impl Trait<N> where u8: Trait<N> {
     2u8
 }
 
-// @has foo/fn.a_sink.html '//pre[@class="rust fn"]' \
+// @has foo/fn.a_sink.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N>'
 pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N> {
     v
 }
 
-// @has foo/fn.b_sink.html '//pre[@class="rust fn"]' \
+// @has foo/fn.b_sink.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub async fn b_sink<const N: usize>(_: impl Trait<N>)'
 pub async fn b_sink<const N: usize>(_: impl Trait<N>) {}
 
-// @has foo/fn.concrete.html '//pre[@class="rust fn"]' \
+// @has foo/fn.concrete.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub fn concrete() -> [u8; 22]'
 pub fn concrete() -> [u8; 3 + std::mem::size_of::<u64>() << 1] {
     Default::default()
 }
 
-// @has foo/type.Faz.html '//pre[@class="rust typedef"]' \
+// @has foo/type.Faz.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'type Faz<const N: usize> = [u8; N];'
 pub type Faz<const N: usize> = [u8; N];
-// @has foo/type.Fiz.html '//pre[@class="rust typedef"]' \
+// @has foo/type.Fiz.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'type Fiz<const N: usize> = [[u8; N]; 48];'
 pub type Fiz<const N: usize> = [[u8; N]; 3 << 4];
 
@@ -91,7 +91,7 @@ macro_rules! define_me {
     }
 }
 
-// @has foo/struct.Foz.html '//pre[@class="rust struct"]' \
+// @has foo/struct.Foz.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub struct Foz<const N: usize>(_);'
 define_me!(Foz<N>);
 
@@ -103,13 +103,13 @@ trait Q {
     const ASSOC: usize = N;
 }
 
-// @has foo/fn.q_user.html '//pre[@class="rust fn"]' \
+// @has foo/fn.q_user.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub fn q_user() -> [u8; 13]'
 pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {
     [0; <[u8; 13] as Q>::ASSOC]
 }
 
-// @has foo/union.Union.html '//pre[@class="rust union"]' \
+// @has foo/union.Union.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub union Union<const N: usize>'
 pub union Union<const N: usize> {
     // @has - //pre "pub arr: [u8; N]"
@@ -118,7 +118,7 @@ pub union Union<const N: usize> {
     pub another_arr: [(); N],
 }
 
-// @has foo/enum.Enum.html '//pre[@class="rust enum"]' \
+// @has foo/enum.Enum.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub enum Enum<const N: usize>'
 pub enum Enum<const N: usize> {
     // @has - //pre "Variant([u8; N])"
index 75ee84279be3c840976325a93401735af5b4c800..726fb8f0c341681af2ca5df0b666ee9dc6643c3e 100644 (file)
@@ -8,7 +8,7 @@ pub enum Order {
     Unsorted,
 }
 
-// @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>'
+// @has foo/struct.VSet.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct VSet<T, const ORDER: Order>'
 // @has foo/struct.VSet.html '//*[@id="impl-Send-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
 // @has foo/struct.VSet.html '//*[@id="impl-Sync-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
 pub struct VSet<T, const ORDER: Order> {
index 215ee228eb857dfba2f05370de52b9390a767dc8..c53cf6dcd0570b4f0717ca79062cb2f35333ee74 100644 (file)
@@ -2,6 +2,6 @@
 #![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
 // make sure that `ConstEvaluatable` predicates dont cause rustdoc to ICE #77647
-// @has foo/struct.Ice.html '//pre[@class="rust struct"]' \
+// @has foo/struct.Ice.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub struct Ice<const N: usize>;'
 pub struct Ice<const N: usize> where [(); N + 1]:;
index ebda5b1940455a2ab5611c7f47d9b6afe3a177f0..72473a112440ce28414f01b479f18dc3e4a789db 100644 (file)
@@ -1,4 +1,4 @@
 #![crate_name = "foo"]
 
-// @has foo/type.CellIndex.html '//pre[@class="rust typedef"]' 'type CellIndex<const D: usize> = [i64; D];'
+// @has foo/type.CellIndex.html '//div[@class="item-decl"]/pre[@class="rust"]' 'type CellIndex<const D: usize> = [i64; D];'
 pub type CellIndex<const D: usize> = [i64; D];
index 2fc486d01dae02b1ed7f2260b001690d96a82fb5..42f6ac7923bf2e12b6a95944a29a69c824ce881c 100644 (file)
@@ -6,20 +6,20 @@
 
 extern "rust-intrinsic" {
     // @has 'foo/fn.transmute.html'
-    // @has - '//pre[@class="rust fn"]' 'pub const unsafe extern "rust-intrinsic" fn transmute<T, U>(_: T) -> U'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub const unsafe extern "rust-intrinsic" fn transmute<T, U>(_: T) -> U'
     #[stable(since="1.0.0", feature="rust1")]
     #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
     pub fn transmute<T, U>(_: T) -> U;
 
     // @has 'foo/fn.unreachable.html'
-    // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
     #[stable(since="1.0.0", feature="rust1")]
     pub fn unreachable() -> !;
 }
 
 extern "C" {
     // @has 'foo/fn.needs_drop.html'
-    // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "C" fn needs_drop() -> !'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "C" fn needs_drop() -> !'
     #[stable(since="1.0.0", feature="rust1")]
     pub fn needs_drop() -> !;
 }
index b3178da98eeb282ecc836c22b5b57937b717451d..5cbe4d59108a4208cf4d828322a43fe41edc94a3 100644 (file)
@@ -1,4 +1,4 @@
-// @has deprecated/index.html '//*[@class="item-left module-item"]/span[@class="stab deprecated"]' \
+// @has deprecated/index.html '//*[@class="item-left"]/span[@class="stab deprecated"]' \
 //      'Deprecated'
 // @has - '//*[@class="item-right docblock-short"]' 'Deprecated docs'
 
index 4f15418650c2d69b49ec2f71f1d235b92e50de62..4d5c9f83e1ee0620009f95150bc47b28ccf84538 100644 (file)
@@ -8,7 +8,7 @@ pub trait Bar {
     fn foo(foo: Self::Fuu);
 }
 
-// @has doc_assoc_item/struct.Foo.html '//*[@class="impl has-srclink"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
+// @has doc_assoc_item/struct.Foo.html '//*[@class="impl"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
 impl<T: Bar<Fuu = u32>> Foo<T> {
     pub fn new(t: T) -> Foo<T> {
         Foo {
index 4cddb0b76d410125eb708e69f86a433156642fdb..1cfbfec6fcd3012e0a847fbaf5a966ee9d0ddf07 100644 (file)
@@ -12,7 +12,7 @@
 // @has doc_cfg/unix_only/index.html \
 //  '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
 //  'Available on Unix only.'
-// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\AARM\Z'
+// @matches - '//*[@class="item-left"]//*[@class="stab portability"]' '\AARM\Z'
 // @count - '//*[@class="stab portability"]' 2
 #[doc(cfg(unix))]
 pub mod unix_only {
@@ -42,7 +42,7 @@ fn unix_and_arm_only_function() {}
 // @has doc_cfg/wasi_only/index.html \
 //  '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
 //  'Available on WASI only.'
-// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\AWebAssembly\Z'
+// @matches - '//*[@class="item-left"]//*[@class="stab portability"]' '\AWebAssembly\Z'
 // @count - '//*[@class="stab portability"]' 2
 #[doc(cfg(target_os = "wasi"))]
 pub mod wasi_only {
@@ -74,7 +74,7 @@ fn wasi_and_wasm32_only_function() {}
 
 // the portability header is different on the module view versus the full view
 // @has doc_cfg/index.html
-// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\Aavx\Z'
+// @matches - '//*[@class="item-left"]//*[@class="stab portability"]' '\Aavx\Z'
 
 // @has doc_cfg/fn.uses_target_feature.html
 // @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
index f2ec8320a05259464874f15483906d95c7581435..46be00a080482818f4af2c588dbdf6612953ea4a 100644 (file)
@@ -1 +1 @@
-<script type="text/json" id="notable-traits-data">{"&amp;'static [SomeStruct]":"&lt;h3&gt;Notable traits for &lt;code&gt;&amp;amp;[&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\"&gt;SomeStruct&lt;/a&gt;]&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait_slice::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &amp;amp;[&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\"&gt;SomeStruct&lt;/a&gt;]&lt;/span&gt;"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"&amp;'static [SomeStruct]":"&lt;h3&gt;Notable traits for &lt;code&gt;&amp;amp;[&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\"&gt;SomeStruct&lt;/a&gt;]&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait_slice::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &amp;amp;[&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\"&gt;SomeStruct&lt;/a&gt;]&lt;/span&gt;"}</script>
\ No newline at end of file
index b426a4d7a8b7ba660183a36e66f09a120dd763f9..f592e3b375c026061ec0fb7274a8eef453f201b5 100644 (file)
@@ -1 +1 @@
-<script type="text/json" id="notable-traits-data">{"SomeStruct":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/span&gt;"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"SomeStruct":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/span&gt;"}</script>
\ No newline at end of file
index 4f8063807e67dc590cbadd4babd5fb0c2b271c68..384be668954000f0a61b53d43cdccd4249881487 100644 (file)
@@ -1 +1 @@
-<script type="text/json" id="notable-traits-data">{"SomeStruct":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/span&gt;","Wrapper&lt;Self&gt;":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl&amp;lt;T:&amp;nbsp;&lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt;&amp;gt; &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/span&gt;"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"SomeStruct":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/span&gt;","Wrapper&lt;Self&gt;":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl&amp;lt;T:&amp;nbsp;&lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt;&amp;gt; &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/span&gt;"}</script>
\ No newline at end of file
index bed2a38b24a2bb1b3421c94d4abc3e05fa6a6a71..0cc1ee10fd33571f268e88aacd0fe54a185e8013 100644 (file)
@@ -1 +1 @@
-<script type="text/json" id="notable-traits-data">{"Wrapper&lt;Self&gt;":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl&amp;lt;T:&amp;nbsp;&lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt;&amp;gt; &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/span&gt;"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"Wrapper&lt;Self&gt;":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl&amp;lt;T:&amp;nbsp;&lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt;&amp;gt; &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/span&gt;"}</script>
\ No newline at end of file
index 18f3900b263b0b7617def5151e60c43519be7d5f..1ac2e52324964a6d40a35a3fa8bbceb489bca114 100644 (file)
@@ -2,8 +2,8 @@
 #![feature(doc_cfg)]
 
 // @has 'foo/index.html'
-// @matches '-' '//*[@class="item-left module-item"]//*[@class="stab portability"]' '^sync$'
-// @has '-' '//*[@class="item-left module-item"]//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only'
+// @matches '-' '//*[@class="item-left"]//*[@class="stab portability"]' '^sync$'
+// @has '-' '//*[@class="item-left"]//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only'
 
 // @has 'foo/struct.Foo.html'
 // @has '-' '//*[@class="stab portability"]' 'sync'
index c1f95ac91c394d7717bda3393d0f97a20d338a7c..4c2071b832266c6fa072bb743d8b8e642778789a 100644 (file)
@@ -3,8 +3,8 @@
 // @has issue_33054/impls/struct.Foo.html
 // @has - '//h3[@class="code-header"]' 'impl Foo'
 // @has - '//h3[@class="code-header"]' 'impl Bar for Foo'
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl"]' 1
 // @has issue_33054/impls/bar/trait.Bar.html
 // @has - '//h3[@class="code-header"]' 'impl Bar for Foo'
 // @count - '//*[@class="struct"]' 1
index 4e901b31c90763e1ef4f965255d609729a389d9c..f32cf310055e0c1da17a3d4ab36fc0c21f08aecb 100644 (file)
@@ -7,7 +7,7 @@
 // blanket implementations.
 
 // @has 'foo/struct.Whatever.html'
-// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl has-srclink"]' 1
+// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl"]' 1
 
 pub trait Something<T> { }
 pub struct Whatever;
index 43971996163022cde80231616b6a78798de5ddb1..e6cff97b184299cfe11db00b9db8f98cd2ba76f9 100644 (file)
@@ -10,7 +10,7 @@
 // There are 3 impl blocks with public item and one that should not be displayed
 // by default because it only contains private items (but not in this case because
 // we used `--document-private-items`).
-// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 4
+// @count - '//*[@class="impl"]' 'impl Foo' 4
 
 // Impl block only containing private items should not be displayed unless the
 // `--document-private-items` flag is used.
index 5caf020658c5f5afaf75ea63535c4aeee62462fa..d44b4a47cee1820590c5b0f3b42d47a82f708392 100644 (file)
@@ -7,7 +7,7 @@
 
 // There are 3 impl blocks with public item and one that should not be displayed
 // because it only contains private items.
-// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 3
+// @count - '//*[@class="impl"]' 'impl Foo' 3
 
 // Impl block only containing private items should not be displayed.
 /// Private
index 95d4db06b3171f7606dbba351238b799682ff2e7..da780580bd087775c41b4caa842bee210aa73656 100644 (file)
@@ -8,7 +8,7 @@
 /// Hello empty impl block!
 impl Foo {}
 // We ensure that this empty impl block without doc isn't rendered.
-// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 1
+// @count - '//*[@class="impl"]' 'impl Foo' 1
 impl Foo {}
 
 // Just to ensure that empty trait impl blocks are rendered.
index 4293d849df52c1893f0c6f323d978bdfb6fc9e9f..96c64ac4e0211b2c09873e337208f6913899e1b9 100644 (file)
@@ -1,5 +1,5 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.f.html
-// @has - '//*[@class="rust fn"]' 'pub fn f(callback: fn(len: usize, foo: u32))'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn f(callback: fn(len: usize, foo: u32))'
 pub fn f(callback: fn(len: usize, foo: u32)) {}
index 66a31c42bcfc7732b52c30387c2cc108eb8154c9..2668b3334979072b15b07e62cb01acba9ca74dab 100644 (file)
@@ -1,5 +1,5 @@
 // @has 'glob_shadowing/index.html'
-// @count - '//div[@class="item-left module-item"]' 6
+// @count - '//div[@class="item-left"]' 6
 // @!has - '//div[@class="item-right docblock-short"]' 'sub1::describe'
 // @has - '//div[@class="item-right docblock-short"]' 'sub2::describe'
 
index 644a6e1cf33c52324035a5dd9d8beaaed3290d16..406157ce26c8093e4de47be334f9d4bf02a03d05 100644 (file)
@@ -63,7 +63,7 @@ impl<const S: Struct, St: Stage + ?Sized> Helper<S> for St {
 // this test as long as one can ensure that private fields are not leaked!
 //
 // @has hide_complex_unevaluated_const_arguments/trait.Sub.html \
-//      '//*[@class="rust trait"]' \
+//      '//div[@class="item-decl"]/pre[@class="rust"]' \
 //      'pub trait Sub: Sup<{ _ }, { _ }> { }'
 pub trait Sub: Sup<{ 90 * 20 * 4 }, { Struct { private: () } }> {}
 
diff --git a/tests/rustdoc/impl-in-const-block.rs b/tests/rustdoc/impl-in-const-block.rs
deleted file mode 100644 (file)
index b44e713..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-// Regression test for #83026.
-// The goal of this test is to ensure that impl blocks inside
-// const expressions are documented as well.
-
-#![crate_name = "foo"]
-
-// @has 'foo/struct.A.html'
-// @has - '//*[@id="method.new"]/*[@class="code-header"]' 'pub fn new() -> A'
-// @has - '//*[@id="method.bar"]/*[@class="code-header"]' 'pub fn bar(&self)'
-// @has - '//*[@id="method.woo"]/*[@class="code-header"]' 'pub fn woo(&self)'
-// @has - '//*[@id="method.yoo"]/*[@class="code-header"]' 'pub fn yoo()'
-// @has - '//*[@id="method.yuu"]/*[@class="code-header"]' 'pub fn yuu()'
-pub struct A;
-
-const _: () = {
-    impl A {
-        const FOO: () = {
-            impl A {
-                pub fn woo(&self) {}
-            }
-        };
-
-        pub fn new() -> A {
-            A
-        }
-    }
-};
-pub const X: () = {
-    impl A {
-        pub fn bar(&self) {}
-    }
-};
-
-fn foo() {
-    impl A {
-        pub fn yoo() {}
-    }
-    const _: () = {
-        impl A {
-            pub fn yuu() {}
-        }
-    };
-}
index 90cbb77cb6b60a013b1b8475bfa9bdde21204227..f7738060e993cced229ee623d27680380959b690 100644 (file)
@@ -5,7 +5,7 @@
 
 pub struct Foo<T> { field: T }
 
-// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has impl_parts/struct.Foo.html '//*[@class="impl"]//h3[@class="code-header"]' \
 //     "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone,"
 // @has impl_parts/trait.AnAutoTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \
 //     "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone,"
index c97644e7f87237384cd3ead7f275f5dcec45ecf3..a4ca928f3331b94068dd7cd89d75dc1f8d8d9cc8 100644 (file)
@@ -4,6 +4,6 @@
 extern crate inline_default_methods;
 
 // @has inline_default_methods/trait.Foo.html
-// @has - '//*[@class="rust trait"]' 'fn bar(&self);'
-// @has - '//*[@class="rust trait"]' 'fn foo(&mut self) { ... }'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn bar(&self);'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn foo(&mut self) { ... }'
 pub use inline_default_methods::Foo;
index cde7f68ff01826c88a1162e43a6c1b626338d600..48672590a12dd969ea7e9daa274c0e86f8a7389c 100644 (file)
@@ -3,3 +3,5 @@
 pub struct SomeStruct;
 
 pub fn some_fn() {}
+
+pub enum Shadowed {}
index f97da11a9014905d7168341b6e7ddf16c9b0e6d6..7a519d2d2554792362e233f75cab42eae31c13b5 100644 (file)
@@ -6,6 +6,11 @@
 
 // @has cross_glob/struct.SomeStruct.html
 // @has cross_glob/fn.some_fn.html
+// @!has cross_glob/enum.Shadowed.html
 // @!has cross_glob/index.html '//code' 'pub use inner::*;'
 #[doc(inline)]
 pub use inner::*;
+
+// This type shadows the glob-imported enum `Shadowed`.
+// @has cross_glob/type.Shadowed.html
+pub type Shadowed = u8;
index fa760540e436596d54dc7c359a1ab4112b5333ac..0da8bfc3a9ae368460d0c44fb3307b30c6515170 100644 (file)
 pub use dyn_trait::Ty3;
 
 // @has user/fn.func0.html
-// @has - '//pre[@class="rust fn"]' "func0(_: &dyn Fn())"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func0(_: &dyn Fn())"
 // FIXME(fmease): Show placeholder-lifetime bound, render "func0(_: &(dyn Fn() + '_))"
 pub use dyn_trait::func0;
 
 // @has user/fn.func1.html
-// @has - '//pre[@class="rust fn"]' "func1<'func>(_: &(dyn Fn() + 'func))"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func1<'func>(_: &(dyn Fn() + 'func))"
 pub use dyn_trait::func1;
index 9c4f646592038e6ec62fe4036f2b47c4aef8f794..e8587209b61655ea358c161a77580a1c4a2e9d22 100644 (file)
@@ -4,37 +4,37 @@
 extern crate impl_trait_aux;
 
 // @has impl_trait/fn.func.html
-// @has - '//pre[@class="rust fn"]' "pub fn func<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)"
-// @!has - '//pre[@class="rust fn"]' 'where'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub fn func<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)"
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where'
 pub use impl_trait_aux::func;
 
 // @has impl_trait/fn.func2.html
-// @has - '//pre[@class="rust fn"]' "func2<T>("
-// @has - '//pre[@class="rust fn"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>,"
-// @has - '//pre[@class="rust fn"]' "_y: impl Iterator<Item = u8>)"
-// @!has - '//pre[@class="rust fn"]' 'where'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func2<T>("
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>,"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_y: impl Iterator<Item = u8>)"
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where'
 pub use impl_trait_aux::func2;
 
 // @has impl_trait/fn.func3.html
-// @has - '//pre[@class="rust fn"]' "func3("
-// @has - '//pre[@class="rust fn"]' "_x: impl Iterator<Item = impl Iterator<Item = u8>> + Clone)"
-// @!has - '//pre[@class="rust fn"]' 'where'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func3("
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_x: impl Iterator<Item = impl Iterator<Item = u8>> + Clone)"
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where'
 pub use impl_trait_aux::func3;
 
 // @has impl_trait/fn.func4.html
-// @has - '//pre[@class="rust fn"]' "func4<T>("
-// @has - '//pre[@class="rust fn"]' "T: Iterator<Item = impl Clone>,"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func4<T>("
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "T: Iterator<Item = impl Clone>,"
 pub use impl_trait_aux::func4;
 
 // @has impl_trait/fn.func5.html
-// @has - '//pre[@class="rust fn"]' "func5("
-// @has - '//pre[@class="rust fn"]' "_f: impl for<'any> Fn(&'any str, &'any str) -> bool + for<'r> Other<T<'r> = ()>,"
-// @has - '//pre[@class="rust fn"]' "_a: impl for<'alpha, 'beta> Auxiliary<'alpha, Item<'beta> = fn(_: &'beta ())>"
-// @!has - '//pre[@class="rust fn"]' 'where'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func5("
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_f: impl for<'any> Fn(&'any str, &'any str) -> bool + for<'r> Other<T<'r> = ()>,"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_a: impl for<'alpha, 'beta> Auxiliary<'alpha, Item<'beta> = fn(_: &'beta ())>"
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where'
 pub use impl_trait_aux::func5;
 
 // @has impl_trait/fn.async_fn.html
-// @has - '//pre[@class="rust fn"]' "pub async fn async_fn()"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn async_fn()"
 pub use impl_trait_aux::async_fn;
 
 // @has impl_trait/struct.Foo.html
index 6e89167b3a4512fa44ccf57466fbbad4beb855c3..571eaf6be967a45771f682f56d4345148da969f3 100644 (file)
@@ -5,8 +5,8 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948_1/struct.Wobble.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for'
 // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
 // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
index 141e07656a09c48b2ac298d73ea1308a8175697c..7eae21046ccbc834bb10a16675038dc19d8b4e7e 100644 (file)
@@ -5,9 +5,9 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948_2/struct.Wobble.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Qux for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for'
 // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
 
index 96fc6ca47e7f656d95691bffaa164e033dbba5fe..9c271bf4ad43fcbe17689de3ddb0dee9d50dcc6e 100644 (file)
@@ -5,9 +5,9 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948/struct.Foo.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for'
-// @!has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bar for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
 // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
 pub use rustdoc_nonreachable_impls::Foo;
 
index 5daa0d4baad6316e25d9cbee998146057771afb3..d5b0de5725bce4f32502d5a7be169517a361cc67 100644 (file)
@@ -6,9 +6,9 @@
 
 extern crate macros;
 
-// @has foo/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab deprecated"]' \
+// @has foo/index.html '//*[@class="item-left unstable deprecated"]/span[@class="stab deprecated"]' \
 //         Deprecated
-// @has - '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab unstable"]' \
+// @has - '//*[@class="item-left unstable deprecated"]/span[@class="stab unstable"]' \
 //         Experimental
 
 // @has foo/macro.my_macro.html
diff --git a/tests/rustdoc/issue-107350.rs b/tests/rustdoc/issue-107350.rs
new file mode 100644 (file)
index 0000000..75f378e
--- /dev/null
@@ -0,0 +1,18 @@
+// This is a regression test for <https://github.com/rust-lang/rust/issues/107350>.
+// It shouldn't loop indefinitely.
+
+#![crate_name = "foo"]
+
+// @has 'foo/oops/enum.OhNo.html'
+
+pub mod oops {
+    pub use crate::oops::OhNo;
+
+    mod inner {
+        pub enum OhNo {
+            Item = 1,
+        }
+    }
+
+    pub use self::inner::*;
+}
index 2589e27f215029de4dd4b19841a9a97a841a518e..a774b0ca7cd7a4ca54324b86e49f17406b641a18 100644 (file)
@@ -13,7 +13,7 @@ pub trait Trait {
 }
 
 // @has issue_20646/fn.fun.html \
-//      '//*[@class="rust fn"]' 'where T: Trait<Output = i32>'
+//      '//div[@class="item-decl"]/pre[@class="rust"]' 'where T: Trait<Output = i32>'
 pub fn fun<T>(_: T) where T: Trait<Output=i32> {}
 
 pub mod reexport {
@@ -21,6 +21,6 @@ pub mod reexport {
     //      '//*[@id="associatedtype.Output"]' \
     //      'type Output'
     // @has issue_20646/reexport/fn.fun.html \
-    //      '//*[@class="rust fn"]' 'where T: Trait<Output = i32>'
+    //      '//div[@class="item-decl"]/pre[@class="rust"]' 'where T: Trait<Output = i32>'
     pub use issue_20646::{Trait, fun};
 }
index 022ff290e1a7153c5c2aff5615596648227466be..026b4f5acc912d7b2eb6889e81d2f20341e1814b 100644 (file)
@@ -5,18 +5,18 @@
 
 // @has issue_20727_2/trait.Add.html
 pub trait Add<RHS = Self> {
-    // @has - '//*[@class="rust trait"]' 'trait Add<RHS = Self> {'
-    // @has - '//*[@class="rust trait"]' 'type Output;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Add<RHS = Self> {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Output;'
     type Output;
 
-    // @has - '//*[@class="rust trait"]' 'fn add(self, rhs: RHS) -> Self::Output;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn add(self, rhs: RHS) -> Self::Output;'
     fn add(self, rhs: RHS) -> Self::Output;
 }
 
 // @has issue_20727_2/reexport/trait.Add.html
 pub mod reexport {
-    // @has - '//*[@class="rust trait"]' 'trait Add<RHS = Self> {'
-    // @has - '//*[@class="rust trait"]' 'type Output;'
-    // @has - '//*[@class="rust trait"]' 'fn add(self, rhs: RHS) -> Self::Output;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Add<RHS = Self> {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Output;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn add(self, rhs: RHS) -> Self::Output;'
     pub use issue_20727::Add;
 }
index 52032b75aeaf5134313acbde842cad7de9fe65e7..741ce8023d7e78bfb58fae0d34cd6e7b27baf512 100644 (file)
@@ -7,18 +7,18 @@ pub trait Bar {}
 
 // @has issue_20727_3/trait.Deref2.html
 pub trait Deref2 {
-    // @has - '//*[@class="rust trait"]' 'trait Deref2 {'
-    // @has - '//*[@class="rust trait"]' 'type Target: Bar;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Deref2 {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Target: Bar;'
     type Target: Bar;
 
-    // @has - '//*[@class="rust trait"]' 'fn deref(&self) -> Self::Target;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn deref(&self) -> Self::Target;'
     fn deref(&self) -> Self::Target;
 }
 
 // @has issue_20727_3/reexport/trait.Deref2.html
 pub mod reexport {
-    // @has - '//*[@class="rust trait"]' 'trait Deref2 {'
-    // @has - '//*[@class="rust trait"]' 'type Target: Bar;'
-    // @has - '//*[@class="rust trait"]' 'fn deref(&self) -> Self::Target;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Deref2 {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Target: Bar;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn deref(&self) -> Self::Target;'
     pub use issue_20727::Deref2;
 }
index 643f93875909390b0b8bf410c325ecfd9393a309..b8fac4da6eadf8288b91c9370d730291873cbed7 100644 (file)
@@ -5,36 +5,36 @@
 
 // @has issue_20727_4/trait.Index.html
 pub trait Index<Idx: ?Sized> {
-    // @has - '//*[@class="rust trait"]' 'trait Index<Idx: ?Sized> {'
-    // @has - '//*[@class="rust trait"]' 'type Output: ?Sized'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Index<Idx: ?Sized> {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Output: ?Sized'
     type Output: ?Sized;
 
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        'fn index(&self, index: Idx) -> &Self::Output'
     fn index(&self, index: Idx) -> &Self::Output;
 }
 
 // @has issue_20727_4/trait.IndexMut.html
 pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        'trait IndexMut<Idx: ?Sized>: Index<Idx> {'
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;'
     fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
 }
 
 pub mod reexport {
     // @has issue_20727_4/reexport/trait.Index.html
-    // @has - '//*[@class="rust trait"]' 'trait Index<Idx>where Idx: ?Sized,{'
-    // @has - '//*[@class="rust trait"]' 'type Output: ?Sized'
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Index<Idx>where Idx: ?Sized,{'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Output: ?Sized'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        'fn index(&self, index: Idx) -> &Self::Output'
     pub use issue_20727::Index;
 
     // @has issue_20727_4/reexport/trait.IndexMut.html
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        'trait IndexMut<Idx>: Index<Idx>where Idx: ?Sized,{'
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;'
     pub use issue_20727::IndexMut;
 }
index c1a98cd57daf8cc66e452bf5fee3991e0e8cacb5..df334821cccc97868e71746592ff6e100c7bb6e6 100644 (file)
@@ -5,20 +5,20 @@
 
 // @has issue_20727/trait.Deref.html
 pub trait Deref {
-    // @has - '//*[@class="rust trait"]' 'trait Deref {'
-    // @has - '//*[@class="rust trait"]' 'type Target: ?Sized;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Deref {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Target: ?Sized;'
     type Target: ?Sized;
 
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //        "fn deref<'a>(&'a self) -> &'a Self::Target;"
     fn deref<'a>(&'a self) -> &'a Self::Target;
 }
 
 // @has issue_20727/reexport/trait.Deref.html
 pub mod reexport {
-    // @has - '//*[@class="rust trait"]' 'trait Deref {'
-    // @has - '//*[@class="rust trait"]' 'type Target: ?Sized;'
-    // @has - '//*[@class="rust trait"]' \
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Deref {'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Target: ?Sized;'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
     //      "fn deref<'a>(&'a self) -> &'a Self::Target;"
     pub use issue_20727::Deref;
 }
index 43ce13fd9b18524e2033b8e5d6b6d2e76bfdb76b..5de26abace6fab01d1b20f6570358578468f4c88 100644 (file)
@@ -7,5 +7,5 @@ impl super::Blah for super::What { }
 pub trait Blah { }
 
 // @count issue_21474/struct.What.html \
-//        '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+//        '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
 pub struct What;
index ff5813dac8099613997ec87ded88393e0f2473d8..19e626ba132356d69889be10f1fe80a42849824e 100644 (file)
@@ -1,19 +1,19 @@
 extern "C" {
     // @has issue_22038/fn.foo1.html \
-    //      '//*[@class="rust fn"]' 'pub unsafe extern "C" fn foo1()'
+    //      '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "C" fn foo1()'
     pub fn foo1();
 }
 
 extern "system" {
     // @has issue_22038/fn.foo2.html \
-    //      '//*[@class="rust fn"]' 'pub unsafe extern "system" fn foo2()'
+    //      '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "system" fn foo2()'
     pub fn foo2();
 }
 
 // @has issue_22038/fn.bar.html \
-//      '//*[@class="rust fn"]' 'pub extern "C" fn bar()'
+//      '//div[@class="item-decl"]/pre[@class="rust"]' 'pub extern "C" fn bar()'
 pub extern "C" fn bar() {}
 
 // @has issue_22038/fn.baz.html \
-//      '//*[@class="rust fn"]' 'pub extern "system" fn baz()'
+//      '//div[@class="item-decl"]/pre[@class="rust"]' 'pub extern "system" fn baz()'
 pub extern "system" fn baz() {}
index 8d2c27cf3d77dc4f40cc75fc9f98cde9c0562cf7..8296d7a81f2b1bc9c49d8d2995e8b030e6a70ca0 100644 (file)
@@ -2,9 +2,9 @@
 #![doc(issue_tracker_base_url = "https://issue_url/")]
 #![unstable(feature = "test", issue = "32374")]
 
-// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab deprecated"]' \
+// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated"]/span[@class="stab deprecated"]' \
 //      'Deprecated'
-// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab unstable"]' \
+// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated"]/span[@class="stab unstable"]' \
 //      'Experimental'
 // @matches issue_32374/index.html '//*[@class="item-right docblock-short"]/text()' 'Docs'
 
index 1e4791e01253df01edcb4aa0c7fdaa5816c6d812..7af00c778361d3042300ba9b8a2ae059aa6fcf07 100644 (file)
@@ -6,23 +6,23 @@ macro_rules! make {
         pub struct S;
 
         // @has issue_33302/constant.CST.html \
-        //        '//pre[@class="rust const"]' 'pub const CST: i32'
+        //        '//div[@class="item-decl"]/pre[@class="rust"]' 'pub const CST: i32'
         pub const CST: i32 = ($n * $n);
         // @has issue_33302/static.ST.html \
-        //        '//pre[@class="rust static"]' 'pub static ST: i32'
+        //        '//div[@class="item-decl"]/pre[@class="rust"]' 'pub static ST: i32'
         pub static ST: i32 = ($n * $n);
 
         pub trait T<X> {
             fn ignore(_: &X) {}
             const C: X;
             // @has issue_33302/trait.T.html \
-            //        '//*[@class="rust trait"]' 'const D: i32'
+            //        '//div[@class="item-decl"]/pre[@class="rust"]' 'const D: i32'
             // @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
             const D: i32 = ($n * $n);
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
+        //        '//*[@class="impl"]' 'impl T<[i32; 16]> for S'
         // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]'
         // @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
         impl T<[i32; ($n * $n)]> for S {
@@ -30,7 +30,7 @@ fn ignore(_: &X) {}
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
+        //        '//*[@class="impl"]' 'impl T<[i32; 16]> for S'
         // @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)'
         // @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32'
         impl T<(i32,)> for S {
@@ -38,7 +38,7 @@ impl T<(i32,)> for S {
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//*[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S'
+        //        '//*[@class="impl"]' 'impl T<(i32, i32)> for S'
         // @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)'
         // @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32'
         impl T<(i32, i32)> for S {
index 86479e6fb2e51a67ef6f2143e67dc8930c3822cf..8a5f0413826a910ff7f7ceaa72db9c2438a4ecd7 100644 (file)
@@ -4,12 +4,12 @@ pub trait Bar<T, U> {}
 
 // @has 'foo/struct.Foo1.html'
 pub struct Foo1;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @has - '//*[@class="impl has-srclink"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
 impl Bar<Foo1, &'static Foo1> for Foo1 {}
 
 // @has 'foo/struct.Foo2.html'
 pub struct Foo2;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @has - '//*[@class="impl has-srclink"]' "impl Bar<&'static Foo2, Foo2> for u8"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8"
 impl Bar<&'static Foo2, Foo2> for u8 {}
index 04bc4f304d68acc8e72e5021b42a22282bee7231..13bedd5dbb023220adaa5721fd43ac78574c9c4a 100644 (file)
@@ -14,7 +14,7 @@ impl<B, C> Signal2 for B where B: Signal<Item = C> {
 // @has - '//h3[@class="code-header"]' 'impl<B> Send for Switch<B>where <B as Signal>::Item: Send'
 // @has - '//h3[@class="code-header"]' 'impl<B> Sync for Switch<B>where <B as Signal>::Item: Sync'
 // @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
 pub struct Switch<B: Signal> {
     pub inner: <B as Signal2>::Item2,
 }
index 1c7aa9c7eefe50c7153bf1b5009a9cc99cc6ca9b..04664805a886f3926abd2e7089eac46958193548 100644 (file)
@@ -7,7 +7,7 @@ pub trait Owned<'a> {
 }
 
 // @has issue_51236/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> Send for Owned<T>where <T as Owned<'static>>::Reader: Send"
 pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
     marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
index c68ffd52186482da0ffe81389f01305b5522ca09..dc1eb304c3d1da377678f20917c56892bbcd4edb 100644 (file)
@@ -12,9 +12,9 @@ macro_rules! array_impls {
 }
 
 // @has issue_53812/trait.MyIterator.html
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>'
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>'
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>'
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>'
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][1]' 'MyStruct<[T; 0]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][2]' 'MyStruct<[T; 1]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][3]' 'MyStruct<[T; 2]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][4]' 'MyStruct<[T; 3]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][5]' 'MyStruct<[T; 10]>'
 array_impls! { 10 3 2 1 0 }
index 7b7290ab4b77c39cf862408852b13a9cd8355832..a886eb0de242c19d57921aaa26747433ad16f65a 100644 (file)
@@ -1,10 +1,10 @@
 pub trait ScopeHandle<'scope> {}
 
 // @has issue_54705/struct.ScopeFutureContents.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'scope, S> Send for ScopeFutureContents<'scope, S>where S: Sync"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'scope, S> Sync for ScopeFutureContents<'scope, S>where S: Sync"
 pub struct ScopeFutureContents<'scope, S>
     where S: ScopeHandle<'scope>,
index 22a18ef90e13ad68b3c57e16f0eda6e45b173c8a..d3c2070d915d67b114961acd04d0e8a0d2fe76b6 100644 (file)
@@ -1,9 +1,9 @@
 #![feature(negative_impls)]
 
 // @has issue_55321/struct.A.html
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl !Send for A"
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl !Sync for A"
 pub struct A();
 
@@ -11,8 +11,8 @@ impl !Send for A {}
 impl !Sync for A {}
 
 // @has issue_55321/struct.B.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> !Send for B<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> !Sync for B<T>"
 pub struct B<T: ?Sized>(A, Box<T>);
index 14a6f5041f2085a6d5ba9f3c8025626d87627d39..b987da30ed29025994221a2ac04dc4cb14946738 100644 (file)
@@ -29,8 +29,8 @@ pub fn bar() {}
 // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo'
 // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar'
 // Though there should be such links later
-// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.foo.html"]' 'foo'
-// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.bar.html"]' 'bar'
+// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left"]/a[@class="fn"][@href="fn.foo.html"]' 'foo'
+// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left"]/a[@class="fn"][@href="fn.bar.html"]' 'bar'
 /// See either [foo] or [bar].
 pub mod subtwo {
 
index b4eef344b5f3b6f01abd00cc4bdae13d9934b496..c9a74335702d585a3e02bd0d8c0440dcf8574aeb 100644 (file)
@@ -17,7 +17,7 @@ impl<'a, T> MyTrait for Inner<'a, T> {
 }
 
 // @has issue_56822/struct.Parser.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'a> Send for Parser<'a>"
 pub struct Parser<'a> {
     field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output
index fbb0f82ae39577701447ddd905e69b7b2723c5f7..e337e4a4f7ad164774044881098725991a45ca57 100644 (file)
@@ -26,9 +26,9 @@ unsafe impl<I> Send for DynTrait<I>
 {}
 
 // @has issue_60726/struct.IntoIter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> !Send for IntoIter<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> !Sync for IntoIter<T>"
 pub struct IntoIter<T>{
     hello:DynTrait<FooInterface<T>>,
index a90e0fea09223064332aa8a094898249a7e9308a..5caea0ec992443b3fdbb469acbbd70ff084b2f11 100644 (file)
@@ -8,7 +8,7 @@ pub const fn bloop() -> i32 {
 pub struct Struct {}
 
 impl Struct {
-    // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' \
+    // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' \
     // 'pub const fn blurp() -> i32'
     /// A useless function that always returns 1.
     pub const fn blurp() -> i32 {
index 2e4bec2544c9d6fd3a655f8de100293487bc63da..d09141c320473933bef1d05874ca5faff4b0901e 100644 (file)
@@ -7,8 +7,8 @@ pub trait AnAmazingTrait {}
 impl<T: Something> AnAmazingTrait for T {}
 
 // @has 'issue_78673/struct.MyStruct.html'
-// @has  - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for MyStruct'
-// @!has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
+// @has  - '//*[@class="impl"]' 'AnAmazingTrait for MyStruct'
+// @!has - '//*[@class="impl"]' 'AnAmazingTrait for T'
 pub struct MyStruct;
 
 impl AnAmazingTrait for MyStruct {}
@@ -16,8 +16,8 @@ impl AnAmazingTrait for MyStruct {}
 // generic structs may have _both_ specific and blanket impls that apply
 
 // @has 'issue_78673/struct.AnotherStruct.html'
-// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for AnotherStruct<()>'
-// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
+// @has - '//*[@class="impl"]' 'AnAmazingTrait for AnotherStruct<()>'
+// @has - '//*[@class="impl"]' 'AnAmazingTrait for T'
 pub struct AnotherStruct<T>(T);
 
 impl<T: Something> Something for AnotherStruct<T> {}
index d3a7a870b580a29d47a4bd3f927962744fad3344..9bce25846d8585dfb35ee558385219a80e812741 100644 (file)
@@ -11,6 +11,6 @@ pub mod prelude {
 #[doc(inline)]
 pub use sub::*;
 
-// @count foo/index.html '//a[@class="mod"][@title="foo::prelude mod"]' 1
+// @count foo/index.html '//a[@class="mod"][@title="mod foo::prelude"]' 1
 // @count foo/prelude/index.html '//div[@class="item-row"]' 0
 pub mod prelude {}
index b836925099364598de36ee0cc1b0ebeb93abc234..d0960dfef436246d1db5206def4790b291b91925 100644 (file)
@@ -8,7 +8,7 @@ pub mod prelude {
     }
 }
 
-// @count foo/index.html '//a[@class="mod"][@title="foo::prelude mod"]' 1
+// @count foo/index.html '//a[@class="mod"][@title="mod foo::prelude"]' 1
 // @count foo/prelude/index.html '//div[@class="item-row"]' 0
 pub mod prelude {}
 
index 3351b5c8350fd7284ac0e7d2598e5c866ee7c9a7..74fc22b31dc0c84cd6956e52bb6aff5173bfd85e 100644 (file)
@@ -5,7 +5,7 @@
 extern crate issue_85454;
 
 // @has foo/trait.FromResidual.html
-// @has - '//pre[@class="rust trait"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
 pub trait FromResidual<R = <Self as Try>::Residual> {
     fn from_residual(residual: R) -> Self;
 }
@@ -24,6 +24,6 @@ pub enum ControlFlow<B, C = ()> {
 
 pub mod reexport {
     // @has foo/reexport/trait.FromResidual.html
-    // @has - '//pre[@class="rust trait"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
     pub use issue_85454::*;
 }
index ff33fb63a0bab20208d3ca2bcb7ac59785a0caa5..3df93eb7cf16f22b81647f079d36f93003f93be8 100644 (file)
@@ -1,2 +1,2 @@
-// @has issue_95873/index.html "//*[@class='item-left import-item']" "pub use ::std as x;"
+// @has issue_95873/index.html "//*[@class='item-left']" "pub use ::std as x;"
 pub use ::std as x;
index d50268509b2c1ababc06f03b2a4d123202869fd3..884b63ac97ffceee0fc6f6033ed96b742372fcbf 100644 (file)
@@ -8,8 +8,8 @@
 
 extern crate issue_98697_reexport_with_anonymous_lifetime;
 
-// @has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'fn repro<F>()where F: Fn(&str)'
-// @!has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'for<'
+// @has issue_98697/fn.repro.html '//div[@class="item-decl"]/pre[@class="rust"]/code' 'fn repro<F>()where F: Fn(&str)'
+// @!has issue_98697/fn.repro.html '//div[@class="item-decl"]/pre[@class="rust"]/code' 'for<'
 pub use issue_98697_reexport_with_anonymous_lifetime::repro;
 
 // @has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header"]' 'impl MyTrait<&Extra> for Extra'
index 41e64726a3246f083267660a677401a2698236ab..ba29a77ebdff8ab41cd2beeaf1490740be4256cc 100644 (file)
@@ -9,6 +9,6 @@
 
 pub use issue_99221_aux::*;
 
-// @count foo/index.html '//a[@class="struct"][@title="foo::Print struct"]' 1
+// @count foo/index.html '//a[@class="struct"][@title="struct foo::Print"]' 1
 
 pub struct Print;
index 3208fea05b3762d05f0943e39de8ee50609aa942..b56ec6e11eafc138dfe8897ef57c64a7aee065d2 100644 (file)
@@ -9,7 +9,7 @@
 
 pub use issue_99734_aux::*;
 
-// @count foo/index.html '//a[@class="fn"][@title="foo::main fn"]' 1
+// @count foo/index.html '//a[@class="fn"][@title="fn foo::main"]' 1
 
 extern "C" {
     pub fn main() -> std::ffi::c_int;
index b2f9b8b46578b870bf91eba1eafdd39654e67f5d..8f5d6fa3d56d366c37f74ff988dbc4d720383c43 100644 (file)
@@ -9,6 +9,6 @@
 
 pub use issue_99734_aux::*;
 
-// @count foo/index.html '//a[@class="mod"][@title="foo::task mod"]' 1
+// @count foo/index.html '//a[@class="mod"][@title="mod foo::task"]' 1
 
 pub mod task {}
index 46a50e2fc30b4b33e3e9004e53d97d593984cb9c..14533624e448e6f059699be88c56dd554d7b34fc 100644 (file)
@@ -2,14 +2,14 @@
 #![feature(rustc_attrs)]
 
 // @has 'foo/fn.foo.html'
-// @has - '//*[@class="rust fn"]' 'fn foo(x: usize, const Y: usize, z: usize) -> [usize; 3]'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn foo(x: usize, const Y: usize, z: usize) -> [usize; 3]'
 #[rustc_legacy_const_generics(1)]
 pub fn foo<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
     [x, Y, z]
 }
 
 // @has 'foo/fn.bar.html'
-// @has - '//*[@class="rust fn"]' 'fn bar(x: usize, const Y: usize, const Z: usize) -> [usize; 3]'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn bar(x: usize, const Y: usize, const Z: usize) -> [usize; 3]'
 #[rustc_legacy_const_generics(1, 2)]
 pub fn bar<const Y: usize, const Z: usize>(x: usize) -> [usize; 3] {
     [x, Y, z]
index 5d30a745a61a6027e4d3c8dab75fb571baff0717..0fb66059109071885e06a42ac2b60cc12db8f26e 100644 (file)
@@ -1,5 +1,5 @@
 #![crate_name = "foo"]
 
 // @has 'foo/type.Resolutions.html'
-// @has - '//*[@class="rust typedef"]' "pub type Resolutions<'tcx> = &'tcx u8;"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub type Resolutions<'tcx> = &'tcx u8;"
 pub type Resolutions<'tcx> = &'tcx u8;
index f3ea6995839174fce43e40925fd7a4dd2a64ee09..431db51d95f7c3a1fb84db3381df8dee6e5e429b 100644 (file)
@@ -5,7 +5,7 @@
 
 pub struct Foo;
 
-// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method has-srclink"]' 2
+// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method"]' 2
 // @!has - '//*[@class="impl-items"]//*[@class="method"]' 'mut'
 impl Foo {
     pub fn foo(mut self) {}
@@ -13,6 +13,6 @@ pub fn foo(mut self) {}
     pub fn bar(mut bar: ()) {}
 }
 
-// @count foo/fn.baz.html '//*[@class="rust fn"]' 1
-// @!has - '//*[@class="rust fn"]' 'mut'
+// @count foo/fn.baz.html '//div[@class="item-decl"]/pre[@class="rust"]' 1
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'mut'
 pub fn baz(mut foo: Foo) {}
index af19c784d6d0514c85cf4cd8148d94778d5d4090..51223af673732931e7557c79f98084a35b13803b 100644 (file)
@@ -5,10 +5,10 @@
 // @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>"
 pub struct Bravo<B>(B);
 
-// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @matches negative_impl/struct.Alpha.html '//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl !Send for Alpha"
 impl !Send for Alpha {}
 
-// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' "\
+// @matches negative_impl/struct.Bravo.html '//*[@class="impl"]//h3[@class="code-header"]' "\
 // impl<B> !Send for Bravo<B>"
 impl<B> !Send for Bravo<B> {}
index db56f68526b3fdce61f5120aea93a29dbc88531c..659480479fd13e9dd747eb52294909696ac08891 100644 (file)
@@ -19,12 +19,12 @@ impl Trait for isize {
     type X = <() as Trait>::X;
 }
 
-// @has 'normalize_assoc_item/fn.f.html' '//pre[@class="rust fn"]' 'pub fn f() -> isize'
+// @has 'normalize_assoc_item/fn.f.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn f() -> isize'
 pub fn f() -> <usize as Trait>::X {
     0
 }
 
-// @has 'normalize_assoc_item/fn.f2.html' '//pre[@class="rust fn"]' 'pub fn f2() -> fn() -> i32'
+// @has 'normalize_assoc_item/fn.f2.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn f2() -> fn() -> i32'
 pub fn f2() -> <isize as Trait>::X {
     todo!()
 }
@@ -49,10 +49,10 @@ impl<Inner: Trait> Trait for Generic<Inner> {
 // These can't be normalized because they depend on a generic parameter.
 // However the user can choose whether the text should be displayed as `Inner::X` or `<Inner as Trait>::X`.
 
-// @has 'normalize_assoc_item/struct.Unknown.html' '//pre[@class="rust struct"]' 'pub struct Unknown<Inner: Trait>(pub <Inner as Trait>::X);'
+// @has 'normalize_assoc_item/struct.Unknown.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct Unknown<Inner: Trait>(pub <Inner as Trait>::X);'
 pub struct Unknown<Inner: Trait>(pub <Inner as Trait>::X);
 
-// @has 'normalize_assoc_item/struct.Unknown2.html' '//pre[@class="rust struct"]' 'pub struct Unknown2<Inner: Trait>(pub Inner::X);'
+// @has 'normalize_assoc_item/struct.Unknown2.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct Unknown2<Inner: Trait>(pub Inner::X);'
 pub struct Unknown2<Inner: Trait>(pub Inner::X);
 
 trait Lifetimes<'a> {
@@ -63,20 +63,20 @@ impl<'a> Lifetimes<'a> for usize {
     type Y = &'a isize;
 }
 
-// @has 'normalize_assoc_item/fn.g.html' '//pre[@class="rust fn"]' "pub fn g() -> &isize"
+// @has 'normalize_assoc_item/fn.g.html' '//div[@class="item-decl"]/pre[@class="rust"]' "pub fn g() -> &isize"
 pub fn g() -> <usize as Lifetimes<'static>>::Y {
     &0
 }
 
-// @has 'normalize_assoc_item/constant.A.html' '//pre[@class="rust const"]' "pub const A: &isize"
+// @has 'normalize_assoc_item/constant.A.html' '//div[@class="item-decl"]/pre[@class="rust"]' "pub const A: &isize"
 pub const A: <usize as Lifetimes<'static>>::Y = &0;
 
 // test cross-crate re-exports
 extern crate inner;
-// @has 'normalize_assoc_item/fn.foo.html' '//pre[@class="rust fn"]' "pub fn foo() -> i32"
+// @has 'normalize_assoc_item/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' "pub fn foo() -> i32"
 pub use inner::foo;
 
-// @has 'normalize_assoc_item/fn.h.html' '//pre[@class="rust fn"]' "pub fn h<T>() -> IntoIter<T, Global>"
+// @has 'normalize_assoc_item/fn.h.html' '//div[@class="item-decl"]/pre[@class="rust"]' "pub fn h<T>() -> IntoIter<T, Global>"
 pub fn h<T>() -> <Vec<T> as IntoIterator>::IntoIter {
     vec![].into_iter()
 }
index 69c89626539319edb39ab24a482171ed24b8ffca..f3811fe0b0ad10781e70e9896016763f0e4886af 100644 (file)
@@ -10,4 +10,4 @@
 pub fn dummy() {}
 
 // ensure that `extern crate foo;` was inserted into code snips automatically:
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20r%23foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0Ause+foo::dummy;%0Adummy();%0A%7D&edition=2015"]' "Run"
index 877ea1cfba15a83cfdd6a1b2fc8c09d087547f45..5c7fa33efc5e586a3be143e52174149497279edb 100644 (file)
@@ -22,6 +22,6 @@
 //! }
 //! ```
 
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run"
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run"
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&version=nightly&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0Aprintln!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' "Run"
index c3a5eb6d324a475513930b35c91dbff969d7b4d3..10efbefd2b168a6f9df2ad6ce74626a4e074ca47 100644 (file)
@@ -13,7 +13,7 @@
 // @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 
 // There should be only one implementation listed.
-// @count - '//*[@class="impl has-srclink"]' 1
+// @count - '//*[@class="impl"]' 1
 // @has - '//*[@id="impl-Foo%3C%26A%3E-for-%26B"]/*[@class="code-header"]' \
 //        'impl<A, B> Foo<&A> for &B'
 #[doc(primitive = "reference")]
index fa7de0aff6a228fdff94fec796f9424e467ae6a9..7115a01d079ff15b99d7befd2badf45028ffb970 100644 (file)
@@ -3,15 +3,15 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.bar.html
-// @has - '//*[@class="rust fn"]' 'pub fn bar() -> '
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn bar() -> '
 /// foo
 pub fn bar() -> usize {
     2
 }
 
 // @has foo/struct.Foo.html
-// @has - '//*[@class="method has-srclink"]' 'pub fn new()'
-// @has - '//*[@class="method has-srclink"]' 'fn not_pub()'
+// @has - '//*[@class="method"]' 'pub fn new()'
+// @has - '//*[@class="method"]' 'fn not_pub()'
 pub struct Foo(usize);
 
 impl Foo {
index 756939ae3773c37fbf9f46c5043d81599aa4888e..bdbcc47c9f28dd4328e3f28c2c9d006277de5efd 100644 (file)
@@ -1,5 +1,5 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.f.html
-// @has - '//*[@class="rust fn"]' 'pub fn f(_: u8)'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn f(_: u8)'
 pub fn f(0u8..=255: u8) {}
index db1f90c69997855b7ad6ad078104eb484f98d8d5..acac0c9919716b067e8b4a7ffdc30e51beebdeba 100644 (file)
@@ -4,12 +4,12 @@
 extern crate reexport_check;
 
 // @!has 'foo/index.html' '//code' 'pub use self::i32;'
-// @has 'foo/index.html' '//div[@class="item-left deprecated module-item"]' 'i32'
+// @has 'foo/index.html' '//div[@class="item-left deprecated"]' 'i32'
 // @has 'foo/i32/index.html'
 #[allow(deprecated, deprecated_in_future)]
 pub use std::i32;
 // @!has 'foo/index.html' '//code' 'pub use self::string::String;'
-// @has 'foo/index.html' '//div[@class="item-left module-item"]' 'String'
+// @has 'foo/index.html' '//div[@class="item-left"]' 'String'
 pub use std::string::String;
 
 // @has 'foo/index.html' '//div[@class="item-right docblock-short"]' 'Docs in original'
index 11364e7f707ef9c7e0d3e4756245907abea61087..35c90ba5d7b894fac9f3e5fa9bb81882031d98d4 100644 (file)
@@ -32,7 +32,7 @@
 // @!has 'foo/enum.BarLocal.html'
 use reexports::BarLocal;
 
-// @has 'foo/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+// @has 'foo/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo()'
 pub use reexports::foo;
 // @!has 'foo/fn.foo_crate.html'
 pub(crate) use reexports::foo_crate;
@@ -41,7 +41,7 @@
 // @!has 'foo/fn.foo_local.html'
 use reexports::foo_local;
 
-// @has 'foo/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+// @has 'foo/type.Type.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub type Type ='
 pub use reexports::Type;
 // @!has 'foo/type.TypeCrate.html'
 pub(crate) use reexports::TypeCrate;
@@ -94,22 +94,22 @@ pub mod inner {
         // @!has 'foo/outer/inner/enum.BarLocal.html'
         use reexports::BarLocal;
 
-        // @has 'foo/outer/inner/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+        // @has 'foo/outer/inner/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo()'
         pub use reexports::foo;
-        // @has 'foo/outer/inner/fn.foo_crate.html' '//*[@class="rust fn"]' 'pub(crate) fn foo_crate()'
+        // @has 'foo/outer/inner/fn.foo_crate.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub(crate) fn foo_crate()'
         pub(crate) use reexports::foo_crate;
-        // @has 'foo/outer/inner/fn.foo_super.html' '//*[@class="rust fn"]' 'pub(in outer) fn foo_super()'
+        // @has 'foo/outer/inner/fn.foo_super.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub(in outer) fn foo_super()'
         pub(super) use::reexports::foo_super;
         // @!has 'foo/outer/inner/fn.foo_self.html'
         pub(self) use reexports::foo_self;
         // @!has 'foo/outer/inner/fn.foo_local.html'
         use reexports::foo_local;
 
-        // @has 'foo/outer/inner/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+        // @has 'foo/outer/inner/type.Type.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub type Type ='
         pub use reexports::Type;
-        // @has 'foo/outer/inner/type.TypeCrate.html' '//*[@class="rust typedef"]' 'pub(crate) type TypeCrate ='
+        // @has 'foo/outer/inner/type.TypeCrate.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub(crate) type TypeCrate ='
         pub(crate) use reexports::TypeCrate;
-        // @has 'foo/outer/inner/type.TypeSuper.html' '//*[@class="rust typedef"]' 'pub(in outer) type TypeSuper ='
+        // @has 'foo/outer/inner/type.TypeSuper.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub(in outer) type TypeSuper ='
         pub(super) use reexports::TypeSuper;
         // @!has 'foo/outer/inner/type.TypeSelf.html'
         pub(self) use reexports::TypeSelf;
index 9aa6d7224baca200e54974cbee5ab25404d18a68..65d305c6d2c4202b7a2b6e6f61e59ed74eb68914 100644 (file)
@@ -31,7 +31,7 @@
 // @!has 'foo/enum.BarLocal.html'
 use reexports::BarLocal;
 
-// @has 'foo/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+// @has 'foo/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo()'
 pub use reexports::foo;
 // @!has 'foo/fn.foo_crate.html'
 pub(crate) use reexports::foo_crate;
@@ -40,7 +40,7 @@
 // @!has 'foo/fn.foo_local.html'
 use reexports::foo_local;
 
-// @has 'foo/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+// @has 'foo/type.Type.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub type Type ='
 pub use reexports::Type;
 // @!has 'foo/type.TypeCrate.html'
 pub(crate) use reexports::TypeCrate;
@@ -93,7 +93,7 @@ pub mod inner {
         // @!has 'foo/outer/inner/enum.BarLocal.html'
         use reexports::BarLocal;
 
-        // @has 'foo/outer/inner/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+        // @has 'foo/outer/inner/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo()'
         pub use reexports::foo;
         // @!has 'foo/outer/inner/fn.foo_crate.html'
         pub(crate) use reexports::foo_crate;
@@ -104,7 +104,7 @@ pub mod inner {
         // @!has 'foo/outer/inner/fn.foo_local.html'
         use reexports::foo_local;
 
-        // @has 'foo/outer/inner/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+        // @has 'foo/outer/inner/type.Type.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub type Type ='
         pub use reexports::Type;
         // @!has 'foo/outer/inner/type.TypeCrate.html'
         pub(crate) use reexports::TypeCrate;
index 7ed9d6729b647a67523462e6ec57a04be926a407..a229a4e29fefb43a2ec580474fa492e3444dfe99 100644 (file)
 
 pub struct S<T>(T);
 
-// @!has foo/trait.Tr.html '//pre[@class="rust trait"]/code/a[@class="trait"]' '~const'
-// @has - '//pre[@class="rust trait"]/code/a[@class="trait"]' 'Clone'
-// @!has - '//pre[@class="rust trait"]/code/span[@class="where"]' '~const'
-// @has - '//pre[@class="rust trait"]/code/span[@class="where"]' ': Clone'
+// @!has foo/trait.Tr.html '//div[@class="item-decl"]/pre[@class="rust"]/code/a[@class="trait"]' '~const'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]/code/span[@class="where"]' '~const'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]/code/span[@class="where"]' ': Clone'
 #[const_trait]
 pub trait Tr<T> {
     // @!has - '//section[@id="method.a"]/h4[@class="code-header"]' '~const'
@@ -45,10 +45,10 @@ fn a<A: ~const Clone + ~const Destruct>()
     }
 }
 
-// @!has foo/fn.foo.html '//pre[@class="rust fn"]/code/a[@class="trait"]' '~const'
-// @has - '//pre[@class="rust fn"]/code/a[@class="trait"]' 'Clone'
-// @!has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' '~const'
-// @has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' ': Clone'
+// @!has foo/fn.foo.html '//div[@class="item-decl"]/pre[@class="rust"]/code/a[@class="trait"]' '~const'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//div[@class="item-decl"]/pre[@class="rust"]/code/span[@class="where fmt-newline"]' '~const'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]/code/span[@class="where fmt-newline"]' ': Clone'
 pub const fn foo<F: ~const Clone + ~const Destruct>()
 where
     Option<F>: ~const Clone + ~const Destruct,
index d08abdaeb1411f45e4cb90fb654e23de1f447362..0b65bf1dfed0fa5f2d3b85bd3c7cefdaec169f6e 100644 (file)
@@ -7,16 +7,16 @@
 
 extern "rust-intrinsic" {
     // @has 'foo/fn.abort.html'
-    // @has - '//pre[@class="rust fn"]' 'pub extern "rust-intrinsic" fn abort() -> !'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub extern "rust-intrinsic" fn abort() -> !'
     #[rustc_safe_intrinsic]
     pub fn abort() -> !;
     // @has 'foo/fn.unreachable.html'
-    // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
     pub fn unreachable() -> !;
 }
 
 extern "C" {
     // @has 'foo/fn.needs_drop.html'
-    // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "C" fn needs_drop() -> !'
+    // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "C" fn needs_drop() -> !'
     pub fn needs_drop() -> !;
 }
index 9a78e963e30363a6ac195cc84c110cd5daef41a8..67137fdcab274a75332d87f977bd365ccaf727c7 100644 (file)
@@ -4,25 +4,25 @@
 pub struct MyBox<T: ?Sized>(*const T);
 
 // @has 'foo/fn.alpha.html'
-// @snapshot link_slice_u32 - '//pre[@class="rust fn"]/code'
+// @snapshot link_slice_u32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn alpha() -> &'static [u32] {
     loop {}
 }
 
 // @has 'foo/fn.beta.html'
-// @snapshot link_slice_generic - '//pre[@class="rust fn"]/code'
+// @snapshot link_slice_generic - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn beta<T>() -> &'static [T] {
     loop {}
 }
 
 // @has 'foo/fn.gamma.html'
-// @snapshot link_box_u32 - '//pre[@class="rust fn"]/code'
+// @snapshot link_box_u32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn gamma() -> MyBox<[u32]> {
     loop {}
 }
 
 // @has 'foo/fn.delta.html'
-// @snapshot link_box_generic - '//pre[@class="rust fn"]/code'
+// @snapshot link_box_generic - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn delta<T>() -> MyBox<[T]> {
     loop {}
 }
index 1d02c13ebfb3c2b9b3ed8d1cf34d94fbb6a8f7eb..5f54b7522ae38774e61e4c8cd7c44dc775ad410b 100644 (file)
@@ -1 +1 @@
-<script type="text/json" id="notable-traits-data">{"Odd":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\"&gt;Odd&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html\" title=\"trait core::iter::traits::iterator::Iterator\"&gt;Iterator&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\"&gt;Odd&lt;/a&gt;&lt;/span&gt;&lt;span class=\"where fmt-newline\"&gt;    type &lt;a href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item\" class=\"associatedtype\"&gt;Item&lt;/a&gt; = &lt;a class=\"primitive\" href=\"{{channel}}/std/primitive.usize.html\"&gt;usize&lt;/a&gt;;&lt;/span&gt;"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"Odd":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\"&gt;Odd&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html\" title=\"trait core::iter::traits::iterator::Iterator\"&gt;Iterator&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\"&gt;Odd&lt;/a&gt;&lt;/span&gt;&lt;span class=\"where fmt-newline\"&gt;    type &lt;a href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item\" class=\"associatedtype\"&gt;Item&lt;/a&gt; = &lt;a class=\"primitive\" href=\"{{channel}}/std/primitive.usize.html\"&gt;usize&lt;/a&gt;;&lt;/span&gt;"}</script>
\ No newline at end of file
index 3c0369e3d3413e221f775561555dd3e37b9d2c28..3bfb43a0bef2c7fed5758002ec0bf30484a185ce 100644 (file)
@@ -4,7 +4,7 @@ struct BodyId {
     hir_id: usize,
 }
 
-// @has 'foo/fn.body_owner.html' '//*[@class="rust fn"]' 'pub fn body_owner(_: BodyId)'
+// @has 'foo/fn.body_owner.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn body_owner(_: BodyId)'
 pub fn body_owner(BodyId { hir_id }: BodyId) {
     // ...
 }
index 7c6a388653c4987a3c766613afc91ccab65d986a..043ac2414883877a8690a1879f0f74151ae20ff6 100644 (file)
@@ -1,8 +1,8 @@
 // @has basic/struct.Foo.html
 // @has - '//h3[@class="code-header"]' 'impl<T> Send for Foo<T>where T: Send'
 // @has - '//h3[@class="code-header"]' 'impl<T> Sync for Foo<T>where T: Sync'
-// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
+// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
 pub struct Foo<T> {
     field: T,
 }
index 43393c21fddb41600b4039250f710337f90469d8..4c39f0bf1e07f20b7a95401496eaed7df7ccf083 100644 (file)
@@ -20,7 +20,7 @@ pub struct Foo<T> {
 }
 
 // @has complex/struct.NotOuter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K>where K: for<'b> Fn((&'b bool, &'a u8)) \
 // -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
 
index 33170a844359b3ca09c2c42a9e7e5963f691f127..71265b3078a06ba91fd3fd4220d6d58ecfa1c1a5 100644 (file)
@@ -9,10 +9,10 @@ unsafe impl<'a, T> Send for Inner<'a, T>
 {}
 
 // @has lifetimes/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'c, K> Send for Foo<'c, K>where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'c, K> Sync for Foo<'c, K>where K: Sync"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
index 77c04ad2ad942af03c327cf708a075a555d7a75c..7fc8447df3efc7963a4e88ec38d17609913ad8e0 100644 (file)
@@ -1,12 +1,12 @@
 // @has manual/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // 'impl<T> Sync for Foo<T>where T: Sync'
 //
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // 'impl<T> Send for Foo<T>'
 //
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 4
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4
 pub struct Foo<T> {
     field: T,
 }
index 2c2c848a5e0fb16db2574bd8015bf3e458b8e39a..97da2d57424cebc94aba9b0b76e6ba42b6e523cf 100644 (file)
@@ -3,10 +3,10 @@ pub struct Inner<T: Copy> {
 }
 
 // @has negative/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> !Send for Outer<T>"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> !Sync for Outer<T>"
 pub struct Outer<T: Copy> {
     inner_field: Inner<T>,
index 423bf115ab165c735a52d857921518db5a7a898d..e4aead71bf2e5a3905689d18c960abd3220bb11a 100644 (file)
@@ -9,10 +9,10 @@ unsafe impl<T> Send for Inner<T>
 }
 
 // @has nested/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // 'impl<T> Send for Foo<T>where T: Copy'
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // 'impl<T> Sync for Foo<T>where T: Sync'
 pub struct Foo<T> {
     inner_field: Inner<T>,
index 59f33623322a928d99a56cfeab77f79c6bb75ed6..ea57d7388b85f174c5dc54f5954ea5f40d9b4819 100644 (file)
@@ -9,7 +9,7 @@ unsafe impl<T> Send for Inner<T>
 }
 
 // @has no_redundancy/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> Send for Outer<T>where T: Send + Copy"
 pub struct Outer<T> {
     inner_field: Inner<T>,
index 558ff2add400cae71a218ba9ffcfb11012cd4f3e..7c9412ae9624364a8573dfda8d2b9da52036e53e 100644 (file)
@@ -23,10 +23,10 @@ unsafe impl<'a, T> Sync for Inner<'a, T>
 }
 
 // @has project/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'c, K> Send for Foo<'c, K>where K: MyTrait<MyItem = bool>, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<'c, K> Sync for Foo<'c, K>where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
 // 'c: 'static,"
 pub struct Foo<'c, K: 'c> {
index c6ae96de77672381bd308742f21f5a528e3f2c6c..145a2b7e00c0a9d64f60d136c14d3844c74c1722 100644 (file)
@@ -23,7 +23,7 @@ impl<T> Pattern for Wrapper<T> {
 
 
 // @has self_referential/struct.WriteAndThen.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<P1> Send for WriteAndThen<P1>where    <P1 as Pattern>::Value: Send"
 pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
     where P1: Pattern;
index 1a76cb919c2989748d476bbbfe3aabdf572ad941..9dc6211ec20b60825c2e8c5ff895c448f5838c55 100644 (file)
@@ -3,7 +3,7 @@ pub trait OwnedTrait<'a> {
 }
 
 // @has static_region/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
 // "impl<T> Send for Owned<T>where <T as OwnedTrait<'static>>::Reader: Send"
 pub struct Owned<T> where T: OwnedTrait<'static> {
     marker: <T as OwnedTrait<'static>>::Reader,
index d9b9c7957d9a1a0fe2357d0417a14c1d2fa978c5..f5fdb1f52bf8ece496e19348de475cee5d5821a1 100644 (file)
@@ -1,5 +1,5 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.foo.html
-// @has - '//*[@class="rust fn"]' "_: &(dyn ToString + 'static)"
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_: &(dyn ToString + 'static)"
 pub fn foo(_: &(ToString + 'static)) {}
index 87240f233ff2afef5e28f90d16d49c1b6d0c9133..5d34ec09b66dc621a2d1bd3b0ddac44acac71f2d 100644 (file)
@@ -81,8 +81,8 @@ pub enum EnumStructVariant {
 }
 
 // @has 'toggle_item_contents/enum.LargeEnum.html'
-// @count - '//*[@class="rust enum"]//details[@class="toggle type-contents-toggle"]' 1
-// @has - '//*[@class="rust enum"]//details[@class="toggle type-contents-toggle"]' 'Show 13 variants'
+// @count - '//div[@class="item-decl"]/pre//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//div[@class="item-decl"]/pre//details[@class="toggle type-contents-toggle"]' 'Show 13 variants'
 pub enum LargeEnum {
     A, B, C, D, E, F(u8), G, H, I, J, K, L, M
 }
index 8ab1143d1f70edb0286e7f51d80affad75d9e046..d72c10f2b2542e9a04df62cb6ddd72da877ea208 100644 (file)
@@ -19,7 +19,7 @@ pub struct Foo(
 );
 
 // @has foo/enum.Bar.html
-// @has - '//pre[@class="rust enum"]' 'BarVariant(String),'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'BarVariant(String),'
 // @matches - '//*[@id="variant.BarVariant.fields"]/h4' '^Tuple Fields$'
 // @has - '//*[@id="variant.BarVariant.field.0"]' '0: String'
 // @has - '//*[@id="variant.BarVariant.fields"]//*[@class="docblock"]' 'Hello docs'
index 62e2f9e7ef24474008caf643c7d04a49eba424c6..e716de8b55c8fdfe3a037eedee8c4d237c9919fb 100644 (file)
@@ -1,20 +1,20 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.tuple0.html //pre 'pub fn tuple0(x: ())'
-// @snapshot link_unit - '//pre[@class="rust fn"]/code'
+// @snapshot link_unit - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn tuple0(x: ()) -> () { x }
 // @has foo/fn.tuple1.html //pre 'pub fn tuple1(x: (i32,)) -> (i32,)'
-// @snapshot link1_i32 - '//pre[@class="rust fn"]/code'
+// @snapshot link1_i32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn tuple1(x: (i32,)) -> (i32,) { x }
 // @has foo/fn.tuple2.html //pre 'pub fn tuple2(x: (i32, i32)) -> (i32, i32)'
-// @snapshot link2_i32 - '//pre[@class="rust fn"]/code'
+// @snapshot link2_i32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn tuple2(x: (i32, i32)) -> (i32, i32) { x }
 // @has foo/fn.tuple1_t.html //pre 'pub fn tuple1_t<T>(x: (T,)) -> (T,)'
-// @snapshot link1_t - '//pre[@class="rust fn"]/code'
+// @snapshot link1_t - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn tuple1_t<T>(x: (T,)) -> (T,) { x }
 // @has foo/fn.tuple2_t.html //pre 'pub fn tuple2_t<T>(x: (T, T)) -> (T, T)'
-// @snapshot link2_t - '//pre[@class="rust fn"]/code'
+// @snapshot link2_t - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn tuple2_t<T>(x: (T, T)) -> (T, T) { x }
 // @has foo/fn.tuple2_tu.html //pre 'pub fn tuple2_tu<T, U>(x: (T, U)) -> (T, U)'
-// @snapshot link2_tu - '//pre[@class="rust fn"]/code'
+// @snapshot link2_tu - '//div[@class="item-decl"]/pre[@class="rust"]/code'
 pub fn tuple2_tu<T, U>(x: (T, U)) -> (T, U) { x }
index d5dfa9484891a66a341c89c723ededde9d2030ee..63e2973c759b6b2b746c81363e16e9858e654f37 100644 (file)
@@ -9,8 +9,8 @@ pub fn method_on_mystruct() {}
 }
 
 // @has typedef/type.MyAlias.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyAlias'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyAlias'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias'
 // @hasraw - 'Alias docstring'
 // @has - '//*[@class="sidebar"]//*[@class="location"]' 'MyAlias'
 // @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
index ae3a6031519fb56a50ea9423c277a2dc31295387..353cd1c477249dae11398e389762048d56f53b9a 100644 (file)
@@ -4,14 +4,14 @@
 
 extern crate unit_return;
 
-// @has 'foo/fn.f0.html' '//*[@class="rust fn"]' 'F: FnMut(u8) + Clone'
+// @has 'foo/fn.f0.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'F: FnMut(u8) + Clone'
 pub fn f0<F: FnMut(u8) + Clone>(f: F) {}
 
-// @has 'foo/fn.f1.html' '//*[@class="rust fn"]' 'F: FnMut(u16) + Clone'
+// @has 'foo/fn.f1.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'F: FnMut(u16) + Clone'
 pub fn f1<F: FnMut(u16) -> () + Clone>(f: F) {}
 
-// @has 'foo/fn.f2.html' '//*[@class="rust fn"]' 'F: FnMut(u32) + Clone'
+// @has 'foo/fn.f2.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'F: FnMut(u32) + Clone'
 pub use unit_return::f2;
 
-// @has 'foo/fn.f3.html' '//*[@class="rust fn"]' 'F: FnMut(u64) + Clone'
+// @has 'foo/fn.f3.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'F: FnMut(u64) + Clone'
 pub use unit_return::f3;
index fe7cad8c3ef84a3d874312b7b3c3a2f6ab7c8140..c0c085e6ac72500d63deb2848063d4f54654b136 100644 (file)
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.foo.html
-// @has - '//*[@class="rust fn"]' 'pub fn foo<X, Y: ?Sized>(_: &X)'
-// @has - '//*[@class="rust fn"]' 'where X: ?Sized,'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo<X, Y: ?Sized>(_: &X)'
+// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where X: ?Sized,'
 pub fn foo<X, Y: ?Sized>(_: &X) where X: ?Sized {}
index 6c1b5d31513526b21c8630f5c6b3e2c39d05864b..f84cb3753cb93a119ab72b7fc3a91eb5c76c0c99 100644 (file)
@@ -1 +1 @@
-<div class="item-decl"><pre class="rust struct"><code>pub struct Simd&lt;T&gt;(_)<br /><span class="where">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre></div>
\ No newline at end of file
+<div class="item-decl"><pre class="rust"><code>pub struct Simd&lt;T&gt;(_)<br /><span class="where">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre></div>
\ No newline at end of file
index d5d6c556d8001464d0576c0cab4461f75ebbaaa7..85b626674274cff6f4f4fd53b3c2e7bdcc9f1251 100644 (file)
@@ -1,4 +1,4 @@
-<div class="item-decl"><pre class="rust trait"><code>pub trait TraitWhere {
+<div class="item-decl"><pre class="rust"><code>pub trait TraitWhere {
     type <a href="#associatedtype.Item" class="associatedtype">Item</a>&lt;'a&gt;<br />&#160;&#160;&#160;&#160;<span class="where">where<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Self: 'a</span>;
 
     fn <a href="#method.func" class="fn">func</a>(self)<br />&#160;&#160;&#160;&#160;<span class="where">where<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span>,
index 8b5bce28f5a2ac4cbc3552fd7d0fb0cb5de95ce5..644a0058244522a55be5bb50683b51130497927e 100644 (file)
@@ -13,7 +13,7 @@ pub fn charlie<C>() where C: MyTrait {}
 
 pub struct Delta<D>(D);
 
-// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has foo/struct.Delta.html '//*[@class="impl"]//h3[@class="code-header"]' \
 //          "impl<D> Delta<D>where D: MyTrait"
 impl<D> Delta<D> where D: MyTrait {
     pub fn delta() {}
@@ -43,7 +43,7 @@ fn lines(self) -> Lines<Self>
     { todo!() }
 }
 
-// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has foo/struct.Echo.html '//*[@class="impl"]//h3[@class="code-header"]' \
 //          "impl<E> MyTrait for Echo<E>where E: MyTrait"
 // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \
 //          "impl<E> MyTrait for Echo<E>where E: MyTrait"
@@ -51,12 +51,12 @@ impl<E> MyTrait for Echo<E>where E: MyTrait {}
 
 pub enum Foxtrot<F> { Foxtrot1(F) }
 
-// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has foo/enum.Foxtrot.html '//*[@class="impl"]//h3[@class="code-header"]' \
 //          "impl<F> MyTrait for Foxtrot<F>where F: MyTrait"
 // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \
 //          "impl<F> MyTrait for Foxtrot<F>where F: MyTrait"
 impl<F> MyTrait for Foxtrot<F>where F: MyTrait {}
 
-// @has foo/type.Golf.html '//pre[@class="rust typedef"]' \
+// @has foo/type.Golf.html '//div[@class="item-decl"]/pre[@class="rust"]' \
 //          "type Golf<T>where T: Clone, = (T, T)"
 pub type Golf<T> where T: Clone = (T, T);
index f7663e4616ae6784ca44d04afe6af378232d98ea..eeb22878f3c63f7c6f4fd1da7e361f5a8f2bcfdb 100644 (file)
@@ -1,4 +1,4 @@
-<div class="item-decl"><pre class="rust enum"><code>pub enum Cow&lt;'a, B&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
-    Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B),
+<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 B</a>),
     Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
 }</code></pre></div>
\ No newline at end of file
index ac7d7759821107d0acaf605772640945441a58c3..c8037c2a8df5a946527d14945c30514be80c0418 100644 (file)
@@ -1,4 +1,4 @@
-<div class="item-decl"><pre class="rust enum"><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),
+<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 B</a>),
     Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
 }</code></pre></div>
\ No newline at end of file
index fa3f224e7ad0f5d21deb3fc66599eb2bd162d3d5..5892270b2f9309aa04495227d0f921c6d539fbbc 100644 (file)
@@ -1,4 +1,4 @@
-<div class="item-decl"><pre class="rust struct"><code>pub struct Struct&lt;'a, B&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
-    pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B,
+<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 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 fb06b0f77c5ce5f2c431f1a84bac8d4362965f52..d3952b0c56699eecd68e68005bb243b737d82285 100644 (file)
@@ -1,4 +1,4 @@
-<div class="item-decl"><pre class="rust struct"><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,
+<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 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 50cfe362328b681749613d4e81a1e01a4c2a1bb8..a2df06e7736af684b7ed8e12eedded83148491b0 100644 (file)
@@ -1,4 +1,4 @@
-<div class="item-decl"><pre class="rust trait"><code>pub trait ToOwned&lt;T&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</span>{
+<div class="item-decl"><pre class="rust"><code>pub trait ToOwned&lt;T&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</span>{
     type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>;
 
     fn <a href="#tymethod.to_owned" class="fn">to_owned</a>(&amp;self) -&gt; Self::<a class="associatedtype" href="trait.ToOwned.html#associatedtype.Owned" title="type foo::ToOwned::Owned">Owned</a>;
index 21eb89b75011b633667482e5547a34933bfab95e..2bfd6f7685a6729dc8e1b2ffbe679978f04eaf58 100644 (file)
@@ -1,4 +1,4 @@
-<div class="item-decl"><pre class="rust trait"><code>pub trait ToOwned2&lt;T:&#160;<a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; {
+<div class="item-decl"><pre class="rust"><code>pub trait ToOwned2&lt;T:&#160;<a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; {
     type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>;
 
     fn <a href="#tymethod.to_owned" class="fn">to_owned</a>(&amp;self) -&gt; Self::<a class="associatedtype" href="trait.ToOwned2.html#associatedtype.Owned" title="type foo::ToOwned2::Owned">Owned</a>;
index 7bb177debc3a8c828e6526c0f5a0e45ba47af870..066f8f87b160b6af62cfce0a1955940fd26c7304 100644 (file)
@@ -1,3 +1,3 @@
-<div class="item-decl"><pre class="rust union"><code>pub union Union&lt;'a, B&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<div class="item-decl"><pre class="rust"><code>pub union Union&lt;'a, B&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
     /* private fields */
 }</code></pre></div>
\ No newline at end of file
index 0d237df53c7f463605bce968c4d96a3d8c0d876b..6b48c5dbd3e2803a1027e8eeec408fd1c9f8472f 100644 (file)
@@ -1,3 +1,3 @@
-<div class="item-decl"><pre class="rust union"><code>pub union Union2&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; {
+<div class="item-decl"><pre class="rust"><code>pub union Union2&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; {
     /* private fields */
 }</code></pre></div>
\ No newline at end of file
index 8d8221bcdf29342cd9a66fa6c73e392ec87c99df..178b8adc3f04af8f6de30df590a7de6e7499430e 100644 (file)
@@ -1,5 +1,5 @@
 use std::fmt::Debug;
 
-// @has 'wrapping/fn.foo.html' '//pre[@class="rust fn"]' 'pub fn foo() -> impl Debug'
-// @count - '//pre[@class="rust fn"]/br' 0
+// @has 'wrapping/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo() -> impl Debug'
+// @count - '//div[@class="item-decl"]/pre[@class="rust"]/br' 0
 pub fn foo() -> impl Debug {}
index c05443488c3ea9748a5473d7641696e5d8520bf9..3f6caecaa5ad0de40e27f2833a550309300839a6 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_hir::intravisit;
 use rustc_hir::Node;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map;
 
 #[no_mangle]
@@ -40,8 +41,9 @@ fn check_fn(
         _: &'tcx hir::FnDecl,
         _: &'tcx hir::Body,
         span: source_map::Span,
-        id: hir::HirId,
+        def_id: LocalDefId,
     ) {
+        let id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
         let item = match cx.tcx.hir().get(id) {
             Node::Item(item) => item,
             _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id).def_id),
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 | }
diff --git a/tests/ui-fulldeps/fluent-messages/missing-message-ref.ftl b/tests/ui-fulldeps/fluent-messages/missing-message-ref.ftl
new file mode 100644 (file)
index 0000000..0cd8229
--- /dev/null
@@ -0,0 +1 @@
+missing_message_ref = {message}
index 4e8147e2b76dce047fe95189e079aab739ee0ed2..74303e97dba947c5b9b1e4605c3566eb865f9eb8 100644 (file)
@@ -96,3 +96,12 @@ mod missing_crate_name {
 
     use self::fluent_generated::{DEFAULT_LOCALE_RESOURCES, test_crate_foo, with_hyphens};
 }
+
+mod missing_message_ref {
+    use super::fluent_messages;
+
+    fluent_messages! {
+        missing => "./missing-message-ref.ftl"
+//~^ ERROR referenced message `message` does not exist
+    }
+}
index d1cd4fe26da27aa3dd9e43168b30e3e2244acbd1..2631b0a623275a08382774ba415aec60889574f9 100644 (file)
@@ -93,6 +93,14 @@ LL |         test_crate => "./missing-crate-name.ftl",
    |
    = help: replace any '-'s with '_'s
 
-error: aborting due to 10 previous errors
+error: referenced message `message` does not exist (in message `missing_message_ref`)
+  --> $DIR/test.rs:104:20
+   |
+LL |         missing => "./missing-message-ref.ftl"
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: you may have meant to use a variable reference (`{$message}`)
+
+error: aborting due to 11 previous errors
 
 For more information about this error, try `rustc --explain E0428`.
index 3f7429a5fccf83cef8b9f289ac2b1d1c36527125..bf655510a5ad88c1051e1bacd8f49e4d25b7eaf3 100644 (file)
@@ -31,6 +31,7 @@ fn main() {
         TyKind::Closure(..) => (),          //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Generator(..) => (),        //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::GeneratorWitness(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::GeneratorWitnessMIR(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Never => (),                //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Tuple(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Alias(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
index 1f49d6b64646f0282b4d214c63f6ecd69f0e1a60..9f8c0bea0eeff5df39bbb7c32df95e0e3bd47e5e 100644 (file)
@@ -121,59 +121,65 @@ LL |         TyKind::GeneratorWitness(..) => (),
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:34:9
    |
-LL |         TyKind::Never => (),
+LL |         TyKind::GeneratorWitnessMIR(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:35:9
    |
-LL |         TyKind::Tuple(..) => (),
+LL |         TyKind::Never => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:36:9
    |
-LL |         TyKind::Alias(..) => (),
+LL |         TyKind::Tuple(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:37:9
    |
-LL |         TyKind::Param(..) => (),
+LL |         TyKind::Alias(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:38:9
    |
-LL |         TyKind::Bound(..) => (),
+LL |         TyKind::Param(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:39:9
    |
-LL |         TyKind::Placeholder(..) => (),
+LL |         TyKind::Bound(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:40:9
    |
-LL |         TyKind::Infer(..) => (),
+LL |         TyKind::Placeholder(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:41:9
    |
+LL |         TyKind::Infer(..) => (),
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
+
+error: usage of `ty::TyKind::<kind>`
+  --> $DIR/ty_tykind_usage.rs:42:9
+   |
 LL |         TyKind::Error(_) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:46:12
+  --> $DIR/ty_tykind_usage.rs:47:12
    |
 LL |     if let TyKind::Int(int_ty) = kind {}
    |            ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:48:24
+  --> $DIR/ty_tykind_usage.rs:49:24
    |
 LL |     fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
    |                        ^^^^^^^^^^
@@ -181,7 +187,7 @@ LL |     fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:50:37
+  --> $DIR/ty_tykind_usage.rs:51:37
    |
 LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    |                                     ^^^^^^^^^^^
@@ -189,7 +195,7 @@ LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:50:53
+  --> $DIR/ty_tykind_usage.rs:51:53
    |
 LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    |                                                     ^^^^^^^^^^^
@@ -197,12 +203,12 @@ LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:53:9
+  --> $DIR/ty_tykind_usage.rs:54:9
    |
 LL |         IrTyKind::Bool
    |         --------^^^^^^
    |         |
    |         help: try using `ty::<kind>` directly: `ty`
 
-error: aborting due to 32 previous errors
+error: aborting due to 33 previous errors
 
index ff1be0804151b58973c1a41c5616e7a3cc5f73df..bdfd9628c48019966b85e7e894fb7d7a6003a4a4 100644 (file)
@@ -2,6 +2,7 @@
 // Testing that a librustc_ast can parse modules with canonicalized base path
 // ignore-cross-compile
 // ignore-remote
+// no-remap-src-base: Reading `file!()` (expectedly) fails when enabled.
 
 #![feature(rustc_private)]
 
index afb7f8fea92a1fae2aa6c205b9e55849c3720ddb..c023d1b1590565bd5fd61d7286780fa0a4f734db 100644 (file)
@@ -16,7 +16,7 @@ LL | fn f1<F>(_: F) where F: Fn(&(), &()) {}
 help: consider borrowing the argument
    |
 LL |     f1(|_: &(), _: &()| {});
-   |            ~~~     ~~~
+   |            +       +
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/anonymous-higher-ranked-lifetime.rs:3:5
@@ -35,8 +35,8 @@ LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f2`
 help: consider borrowing the argument
    |
-LL |     f2(|_: &'a (), _: &()| {});
-   |            ~~~~~~     ~~~
+LL |     f2(|_: &(), _: &()| {});
+   |            +       +
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5
@@ -56,7 +56,7 @@ LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {}
 help: consider borrowing the argument
    |
 LL |     f3(|_: &(), _: &()| {});
-   |            ~~~     ~~~
+   |            +       +
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/anonymous-higher-ranked-lifetime.rs:5:5
@@ -75,8 +75,8 @@ LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f4`
 help: consider borrowing the argument
    |
-LL |     f4(|_: &(), _: &'r ()| {});
-   |            ~~~     ~~~~~~
+LL |     f4(|_: &(), _: &()| {});
+   |            +       +
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
@@ -95,17 +95,15 @@ LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f5`
 help: consider borrowing the argument
    |
-LL |     f5(|_: &'r (), _: &'r ()| {});
-   |            ~~~~~~     ~~~~~~
+LL |     f5(|_: &(), _: &()| {});
+   |            +       +
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/anonymous-higher-ranked-lifetime.rs:7:5
    |
 LL |     g1(|_: (), _: ()| {});
-   |     ^^ --------------
-   |     |  |   |
-   |     |  |   help: consider borrowing the argument: `&()`
-   |     |  found signature defined here
+   |     ^^ -------------- found signature defined here
+   |     |
    |     expected due to this
    |
    = note: expected closure signature `for<'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _`
@@ -115,15 +113,17 @@ note: required by a bound in `g1`
    |
 LL | fn g1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g1`
+help: consider borrowing the argument
+   |
+LL |     g1(|_: &(), _: ()| {});
+   |            +
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
    |
 LL |     g2(|_: (), _: ()| {});
-   |     ^^ --------------
-   |     |  |   |
-   |     |  |   help: consider borrowing the argument: `&()`
-   |     |  found signature defined here
+   |     ^^ -------------- found signature defined here
+   |     |
    |     expected due to this
    |
    = note: expected closure signature `for<'a> fn(&'a (), for<'a> fn(&'a ())) -> _`
@@ -133,15 +133,17 @@ note: required by a bound in `g2`
    |
 LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {}
    |                         ^^^^^^^^^^^^^^^^ required by this bound in `g2`
+help: consider borrowing the argument
+   |
+LL |     g2(|_: &(), _: ()| {});
+   |            +
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5
    |
 LL |     g3(|_: (), _: ()| {});
-   |     ^^ --------------
-   |     |  |   |
-   |     |  |   help: consider borrowing the argument: `&'s ()`
-   |     |  found signature defined here
+   |     ^^ -------------- found signature defined here
+   |     |
    |     expected due to this
    |
    = note: expected closure signature `for<'s> fn(&'s (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _`
@@ -151,15 +153,17 @@ note: required by a bound in `g3`
    |
 LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<dyn Fn(&())>) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g3`
+help: consider borrowing the argument
+   |
+LL |     g3(|_: &(), _: ()| {});
+   |            +
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
    |
 LL |     g4(|_: (), _: ()| {});
-   |     ^^ --------------
-   |     |  |   |
-   |     |  |   help: consider borrowing the argument: `&()`
-   |     |  found signature defined here
+   |     ^^ -------------- found signature defined here
+   |     |
    |     expected due to this
    |
    = note: expected closure signature `for<'a> fn(&'a (), for<'r> fn(&'r ())) -> _`
@@ -169,6 +173,10 @@ note: required by a bound in `g4`
    |
 LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g4`
+help: consider borrowing the argument
+   |
+LL |     g4(|_: &(), _: ()| {});
+   |            +
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5
@@ -188,7 +196,7 @@ LL | fn h1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>, &(), fn(&(), &())) {}
 help: consider borrowing the argument
    |
 LL |     h1(|_: &(), _: (), _: &(), _: ()| {});
-   |            ~~~            ~~~
+   |            +              +
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
@@ -207,8 +215,8 @@ LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<dyn Fn(&())>, &'t0 (), fn(&(),
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `h2`
 help: consider borrowing the argument
    |
-LL |     h2(|_: &(), _: (), _: &'t0 (), _: ()| {});
-   |            ~~~            ~~~~~~~
+LL |     h2(|_: &(), _: (), _: &(), _: ()| {});
+   |            +              +
 
 error: aborting due to 11 previous errors
 
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 f1677b822b4c97f7ef3d7340270170cb1c15773b..50fa7d1ac4d43635cdefc031274550538bd3e8c7 100644 (file)
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
 LL |     type Assoc = T;
    |                  ^ the trait `Copy` is not implemented for `T`
    |
+note: required for `<T as Complete>::Assoc` to implement `Partial<T>`
+  --> $DIR/issue-43784-associated-type.rs:1:11
+   |
+LL | pub trait Partial<X: ?Sized>: Copy {
+   |           ^^^^^^^
 note: required by a bound in `Complete::Assoc`
   --> $DIR/issue-43784-associated-type.rs:5:17
    |
diff --git a/tests/ui/async-await/async-await-let-else.drop_tracking.stderr b/tests/ui/async-await/async-await-let-else.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..fb83ca9
--- /dev/null
@@ -0,0 +1,106 @@
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:48:13
+   |
+LL |     is_send(foo(Some(true)));
+   |             ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:11:14
+   |
+LL |         let r = Rc::new(());
+   |             - has type `Rc<()>` which is not `Send`
+LL |         bar().await
+   |              ^^^^^^ await occurs here, with `r` maybe used later
+LL |     };
+   |     - `r` is later dropped here
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:19:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error[E0277]: `Rc<()>` cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:50:13
+   |
+LL | async fn foo2(x: Option<bool>) {
+   |                                - within this `impl Future<Output = ()>`
+...
+LL |     is_send(foo2(Some(true)));
+   |     ------- ^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: required because it's used within this `async fn` body
+  --> $DIR/async-await-let-else.rs:27:29
+   |
+LL |   async fn bar2<T>(_: T) -> ! {
+   |  _____________________________^
+LL | |     panic!()
+LL | | }
+   | |_^
+   = note: required because it captures the following types: `ResumeTy`, `Option<bool>`, `impl Future<Output = !>`, `()`
+note: required because it's used within this `async fn` body
+  --> $DIR/async-await-let-else.rs:21:32
+   |
+LL |   async fn foo2(x: Option<bool>) {
+   |  ________________________________^
+LL | |     let Some(_) = x else {
+LL | |         bar2(Rc::new(())).await
+LL | |     };
+LL | | }
+   | |_^
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:19:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:52:13
+   |
+LL |     is_send(foo3(Some(true)));
+   |             ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:33:28
+   |
+LL |         (Rc::new(()), bar().await);
+   |          -----------       ^^^^^^ - `Rc::new(())` is later dropped here
+   |          |                 |
+   |          |                 await occurs here, with `Rc::new(())` maybe used later
+   |          has type `Rc<()>` which is not `Send`
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:19:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:54:13
+   |
+LL |     is_send(foo4(Some(true)));
+   |             ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:41:14
+   |
+LL |         let r = Rc::new(());
+   |             - has type `Rc<()>` which is not `Send`
+LL |         bar().await;
+   |              ^^^^^^ await occurs here, with `r` maybe used later
+...
+LL |     };
+   |     - `r` is later dropped here
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:19:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/async-await-let-else.drop_tracking_mir.stderr b/tests/ui/async-await/async-await-let-else.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..c284bbf
--- /dev/null
@@ -0,0 +1,100 @@
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:48:13
+   |
+LL |     is_send(foo(Some(true)));
+   |             ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:11:14
+   |
+LL |         let r = Rc::new(());
+   |             - has type `Rc<()>` which is not `Send`
+LL |         bar().await
+   |              ^^^^^^ await occurs here, with `r` maybe used later
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:19:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error[E0277]: `Rc<()>` cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:50:13
+   |
+LL | async fn foo2(x: Option<bool>) {
+   |                                - within this `impl Future<Output = ()>`
+...
+LL |     is_send(foo2(Some(true)));
+   |     ------- ^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: required because it's used within this `async fn` body
+  --> $DIR/async-await-let-else.rs:27:29
+   |
+LL |   async fn bar2<T>(_: T) -> ! {
+   |  _____________________________^
+LL | |     panic!()
+LL | | }
+   | |_^
+   = note: required because it captures the following types: `impl Future<Output = !>`
+note: required because it's used within this `async fn` body
+  --> $DIR/async-await-let-else.rs:21:32
+   |
+LL |   async fn foo2(x: Option<bool>) {
+   |  ________________________________^
+LL | |     let Some(_) = x else {
+LL | |         bar2(Rc::new(())).await
+LL | |     };
+LL | | }
+   | |_^
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:19:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:52:13
+   |
+LL |     is_send(foo3(Some(true)));
+   |             ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:33:28
+   |
+LL |         (Rc::new(()), bar().await);
+   |          -----------       ^^^^^^ await occurs here, with `Rc::new(())` maybe used later
+   |          |
+   |          has type `Rc<()>` which is not `Send`
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:19:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:54:13
+   |
+LL |     is_send(foo4(Some(true)));
+   |             ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:41:14
+   |
+LL |         let r = Rc::new(());
+   |             - has type `Rc<()>` which is not `Send`
+LL |         bar().await;
+   |              ^^^^^^ await occurs here, with `r` maybe used later
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:19:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/async-await-let-else.no_drop_tracking.stderr b/tests/ui/async-await/async-await-let-else.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..d3c5e80
--- /dev/null
@@ -0,0 +1,90 @@
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:48:13
+   |
+LL |     is_send(foo(Some(true)));
+   |             ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:11:14
+   |
+LL |         let r = Rc::new(());
+   |             - has type `Rc<()>` which is not `Send`
+LL |         bar().await
+   |              ^^^^^^ await occurs here, with `r` maybe used later
+LL |     };
+   |     - `r` is later dropped here
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:19:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:50:13
+   |
+LL |     is_send(foo2(Some(true)));
+   |             ^^^^^^^^^^^^^^^^ future returned by `foo2` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:23:26
+   |
+LL |         bar2(Rc::new(())).await
+   |              ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later
+   |              |
+   |              has type `Rc<()>` which is not `Send`
+LL |     };
+   |     - `Rc::new(())` is later dropped here
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:19:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:52:13
+   |
+LL |     is_send(foo3(Some(true)));
+   |             ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:33:28
+   |
+LL |         (Rc::new(()), bar().await);
+   |          -----------       ^^^^^^ - `Rc::new(())` is later dropped here
+   |          |                 |
+   |          |                 await occurs here, with `Rc::new(())` maybe used later
+   |          has type `Rc<()>` which is not `Send`
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:19:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:54:13
+   |
+LL |     is_send(foo4(Some(true)));
+   |             ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:41:14
+   |
+LL |         let r = Rc::new(());
+   |             - has type `Rc<()>` which is not `Send`
+LL |         bar().await;
+   |              ^^^^^^ await occurs here, with `r` maybe used later
+...
+LL |     };
+   |     - `r` is later dropped here
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:19:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: aborting due to 4 previous errors
+
index 3fb2142b9e5d8aca7862bf960a1cc785da689d70..113d576b5e762cfba33f6ee12d0631636cc88a34 100644 (file)
@@ -1,7 +1,7 @@
 // edition:2021
-// revisions: drop-tracking no-drop-tracking
-// [drop-tracking] compile-flags: -Zdrop-tracking=yes
-// [no-drop-tracking] compile-flags: -Zdrop-tracking=no
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 
 use std::rc::Rc;
 
diff --git a/tests/ui/async-await/async-error-span.drop_tracking.stderr b/tests/ui/async-await/async-error-span.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..c6257cb
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0277]: `()` is not a future
+  --> $DIR/async-error-span.rs:10:20
+   |
+LL | fn get_future() -> impl Future<Output = ()> {
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
+   |
+   = help: the trait `Future` is not implemented for `()`
+   = note: () must be a future or must implement `IntoFuture` to be awaited
+
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/async-error-span.rs:16:9
+   |
+LL |     let a;
+   |         ^ cannot infer type
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/async-error-span.rs:19:17
+   |
+LL |     get_future().await;
+   |                 ^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0698.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/async-error-span.drop_tracking_mir.stderr b/tests/ui/async-await/async-error-span.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..2f29ee6
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0277]: `()` is not a future
+  --> $DIR/async-error-span.rs:10:20
+   |
+LL | fn get_future() -> impl Future<Output = ()> {
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
+   |
+   = help: the trait `Future` is not implemented for `()`
+   = note: () must be a future or must implement `IntoFuture` to be awaited
+
+error[E0282]: type annotations needed
+  --> $DIR/async-error-span.rs:16:9
+   |
+LL |     let a;
+   |         ^
+   |
+help: consider giving `a` an explicit type
+   |
+LL |     let a: /* Type */;
+   |          ++++++++++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0282.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/async-error-span.no_drop_tracking.stderr b/tests/ui/async-await/async-error-span.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..c6257cb
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0277]: `()` is not a future
+  --> $DIR/async-error-span.rs:10:20
+   |
+LL | fn get_future() -> impl Future<Output = ()> {
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
+   |
+   = help: the trait `Future` is not implemented for `()`
+   = note: () must be a future or must implement `IntoFuture` to be awaited
+
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/async-error-span.rs:16:9
+   |
+LL |     let a;
+   |         ^ cannot infer type
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/async-error-span.rs:19:17
+   |
+LL |     get_future().await;
+   |                 ^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0698.
+For more information about an error, try `rustc --explain E0277`.
index 86d459bf084b1f6827c92525f8dc317f518ac7b9..c9ecf359e3de59bdd0effb82a030ad73e3df4e18 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2018
 
 // Regression test for issue #62382.
@@ -10,7 +13,9 @@ fn get_future() -> impl Future<Output = ()> {
 }
 
 async fn foo() {
-    let a; //~ ERROR type inside `async fn` body must be known in this context
+    let a;
+    //[no_drop_tracking,drop_tracking]~^ ERROR type inside `async fn` body must be known in this context
+    //[drop_tracking_mir]~^^ ERROR type annotations needed
     get_future().await;
 }
 
diff --git a/tests/ui/async-await/async-error-span.stderr b/tests/ui/async-await/async-error-span.stderr
deleted file mode 100644 (file)
index 7d4447b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0277]: `()` is not a future
-  --> $DIR/async-error-span.rs:7:20
-   |
-LL | fn get_future() -> impl Future<Output = ()> {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
-   |
-   = help: the trait `Future` is not implemented for `()`
-   = note: () must be a future or must implement `IntoFuture` to be awaited
-
-error[E0698]: type inside `async fn` body must be known in this context
-  --> $DIR/async-error-span.rs:13:9
-   |
-LL |     let a;
-   |         ^ cannot infer type
-   |
-note: the type is part of the `async fn` body because of this `await`
-  --> $DIR/async-error-span.rs:14:17
-   |
-LL |     get_future().await;
-   |                 ^^^^^^
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0277, E0698.
-For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/async-fn-nonsend.drop_tracking.stderr b/tests/ui/async-await/async-fn-nonsend.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..0f0dc33
--- /dev/null
@@ -0,0 +1,49 @@
+error: future cannot be sent between threads safely
+  --> $DIR/async-fn-nonsend.rs:72:17
+   |
+LL |     assert_send(non_send_temporary_in_match());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-fn-nonsend.rs:36:25
+   |
+LL |     match Some(non_send()) {
+   |           ---------------- has type `Option<impl Debug>` which is not `Send`
+LL |         Some(_) => fut().await,
+   |                         ^^^^^^ await occurs here, with `Some(non_send())` maybe used later
+...
+LL | }
+   | - `Some(non_send())` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/async-fn-nonsend.rs:67:24
+   |
+LL | fn assert_send(_: impl Send) {}
+   |                        ^^^^ required by this bound in `assert_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-fn-nonsend.rs:74:17
+   |
+LL |     assert_send(non_sync_with_method_call());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-fn-nonsend.rs:49:14
+   |
+LL |     let f: &mut std::fmt::Formatter = &mut get_formatter();
+   |                                            --------------- has type `Formatter<'_>` which is not `Send`
+...
+LL |         fut().await;
+   |              ^^^^^^ await occurs here, with `get_formatter()` maybe used later
+LL |     }
+LL | }
+   | - `get_formatter()` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/async-fn-nonsend.rs:67:24
+   |
+LL | fn assert_send(_: impl Send) {}
+   |                        ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/async-await/async-fn-nonsend.drop_tracking_mir.stderr b/tests/ui/async-await/async-fn-nonsend.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..57a0128
--- /dev/null
@@ -0,0 +1,43 @@
+error: future cannot be sent between threads safely
+  --> $DIR/async-fn-nonsend.rs:72:17
+   |
+LL |     assert_send(non_send_temporary_in_match());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-fn-nonsend.rs:36:25
+   |
+LL |     match Some(non_send()) {
+   |           ---------------- has type `Option<impl Debug>` which is not `Send`
+LL |         Some(_) => fut().await,
+   |                         ^^^^^^ await occurs here, with `Some(non_send())` maybe used later
+note: required by a bound in `assert_send`
+  --> $DIR/async-fn-nonsend.rs:67:24
+   |
+LL | fn assert_send(_: impl Send) {}
+   |                        ^^^^ required by this bound in `assert_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-fn-nonsend.rs:74:17
+   |
+LL |     assert_send(non_sync_with_method_call());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-fn-nonsend.rs:49:14
+   |
+LL |     let f: &mut std::fmt::Formatter = &mut get_formatter();
+   |                                            --------------- has type `Formatter<'_>` which is not `Send`
+...
+LL |         fut().await;
+   |              ^^^^^^ await occurs here, with `get_formatter()` maybe used later
+note: required by a bound in `assert_send`
+  --> $DIR/async-fn-nonsend.rs:67:24
+   |
+LL | fn assert_send(_: impl Send) {}
+   |                        ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/async-await/async-fn-nonsend.no_drop_tracking.stderr b/tests/ui/async-await/async-fn-nonsend.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..5cec21d
--- /dev/null
@@ -0,0 +1,120 @@
+error: future cannot be sent between threads safely
+  --> $DIR/async-fn-nonsend.rs:70:17
+   |
+LL |     assert_send(local_dropped_before_await());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-fn-nonsend.rs:27:10
+   |
+LL |     let x = non_send();
+   |         - has type `impl Debug` which is not `Send`
+LL |     drop(x);
+LL |     fut().await;
+   |          ^^^^^^ await occurs here, with `x` maybe used later
+LL | }
+   | - `x` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/async-fn-nonsend.rs:67:24
+   |
+LL | fn assert_send(_: impl Send) {}
+   |                        ^^^^ required by this bound in `assert_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-fn-nonsend.rs:72:17
+   |
+LL |     assert_send(non_send_temporary_in_match());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-fn-nonsend.rs:36:25
+   |
+LL |     match Some(non_send()) {
+   |                ---------- has type `impl Debug` which is not `Send`
+LL |         Some(_) => fut().await,
+   |                         ^^^^^^ await occurs here, with `non_send()` maybe used later
+...
+LL | }
+   | - `non_send()` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/async-fn-nonsend.rs:67:24
+   |
+LL | fn assert_send(_: impl Send) {}
+   |                        ^^^^ required by this bound in `assert_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-fn-nonsend.rs:74:17
+   |
+LL |     assert_send(non_sync_with_method_call());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-fn-nonsend.rs:49:14
+   |
+LL |     let f: &mut std::fmt::Formatter = &mut get_formatter();
+   |                                            --------------- has type `Formatter<'_>` which is not `Send`
+...
+LL |         fut().await;
+   |              ^^^^^^ await occurs here, with `get_formatter()` maybe used later
+LL |     }
+LL | }
+   | - `get_formatter()` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/async-fn-nonsend.rs:67:24
+   |
+LL | fn assert_send(_: impl Send) {}
+   |                        ^^^^ required by this bound in `assert_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-fn-nonsend.rs:76:17
+   |
+LL |     assert_send(non_sync_with_method_call_panic());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call_panic` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-fn-nonsend.rs:56:14
+   |
+LL |     let f: &mut std::fmt::Formatter = panic!();
+   |         - has type `&mut Formatter<'_>` which is not `Send`
+LL |     if non_sync().fmt(f).unwrap() == () {
+LL |         fut().await;
+   |              ^^^^^^ await occurs here, with `f` maybe used later
+LL |     }
+LL | }
+   | - `f` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/async-fn-nonsend.rs:67:24
+   |
+LL | fn assert_send(_: impl Send) {}
+   |                        ^^^^ required by this bound in `assert_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-fn-nonsend.rs:78:17
+   |
+LL |     assert_send(non_sync_with_method_call_infinite_loop());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call_infinite_loop` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-fn-nonsend.rs:63:14
+   |
+LL |     let f: &mut std::fmt::Formatter = loop {};
+   |         - has type `&mut Formatter<'_>` which is not `Send`
+LL |     if non_sync().fmt(f).unwrap() == () {
+LL |         fut().await;
+   |              ^^^^^^ await occurs here, with `f` maybe used later
+LL |     }
+LL | }
+   | - `f` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/async-fn-nonsend.rs:67:24
+   |
+LL | fn assert_send(_: impl Send) {}
+   |                        ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 5 previous errors
+
index d7f8d7ac546c052884c439298b52ff48e66e413b..ed440bd0182a6d4ac338ca2bdb307e778abc1c5b 100644 (file)
@@ -1,5 +1,8 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2018
-// compile-flags: --crate-type lib -Zdrop-tracking
+// compile-flags: --crate-type lib
 
 use std::{cell::RefCell, fmt::Debug, rc::Rc};
 
@@ -65,10 +68,13 @@ fn assert_send(_: impl Send) {}
 
 pub fn pass_assert() {
     assert_send(local_dropped_before_await());
+    //[no_drop_tracking]~^ ERROR future cannot be sent between threads safely
     assert_send(non_send_temporary_in_match());
     //~^ ERROR future cannot be sent between threads safely
     assert_send(non_sync_with_method_call());
     //~^ ERROR future cannot be sent between threads safely
     assert_send(non_sync_with_method_call_panic());
+    //[no_drop_tracking]~^ ERROR future cannot be sent between threads safely
     assert_send(non_sync_with_method_call_infinite_loop());
+    //[no_drop_tracking]~^ ERROR future cannot be sent between threads safely
 }
index a7b872fe4444aecd4317b3671d8c58125d1a7549..0f0dc335e7f27cad0cfec72ccc3cc110f38ede13 100644 (file)
@@ -1,12 +1,12 @@
 error: future cannot be sent between threads safely
-  --> $DIR/async-fn-nonsend.rs:68:17
+  --> $DIR/async-fn-nonsend.rs:72:17
    |
 LL |     assert_send(non_send_temporary_in_match());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
 note: future is not `Send` as this value is used across an await
-  --> $DIR/async-fn-nonsend.rs:33:25
+  --> $DIR/async-fn-nonsend.rs:36:25
    |
 LL |     match Some(non_send()) {
    |           ---------------- has type `Option<impl Debug>` which is not `Send`
@@ -16,20 +16,20 @@ LL |         Some(_) => fut().await,
 LL | }
    | - `Some(non_send())` is later dropped here
 note: required by a bound in `assert_send`
-  --> $DIR/async-fn-nonsend.rs:64:24
+  --> $DIR/async-fn-nonsend.rs:67:24
    |
 LL | fn assert_send(_: impl Send) {}
    |                        ^^^^ required by this bound in `assert_send`
 
 error: future cannot be sent between threads safely
-  --> $DIR/async-fn-nonsend.rs:70:17
+  --> $DIR/async-fn-nonsend.rs:74:17
    |
 LL |     assert_send(non_sync_with_method_call());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write`
 note: future is not `Send` as this value is used across an await
-  --> $DIR/async-fn-nonsend.rs:46:14
+  --> $DIR/async-fn-nonsend.rs:49:14
    |
 LL |     let f: &mut std::fmt::Formatter = &mut get_formatter();
    |                                            --------------- has type `Formatter<'_>` which is not `Send`
@@ -40,7 +40,7 @@ LL |     }
 LL | }
    | - `get_formatter()` is later dropped here
 note: required by a bound in `assert_send`
-  --> $DIR/async-fn-nonsend.rs:64:24
+  --> $DIR/async-fn-nonsend.rs:67:24
    |
 LL | fn assert_send(_: impl Send) {}
    |                        ^^^^ required by this bound in `assert_send`
diff --git a/tests/ui/async-await/auxiliary/issue-107036.rs b/tests/ui/async-await/auxiliary/issue-107036.rs
new file mode 100644 (file)
index 0000000..c3f6141
--- /dev/null
@@ -0,0 +1,12 @@
+// edition:2021
+
+pub trait T {}
+impl T for () {}
+
+pub struct S {}
+
+impl S {
+    pub async fn f<'a>(&self) -> impl T + 'a {
+        ()
+    }
+}
diff --git a/tests/ui/async-await/await-sequence.rs b/tests/ui/async-await/await-sequence.rs
new file mode 100644 (file)
index 0000000..726c428
--- /dev/null
@@ -0,0 +1,21 @@
+// edition:2021
+// compile-flags: -Z drop-tracking
+// build-pass
+
+use std::collections::HashMap;
+
+fn main() {
+    let _ = real_main();
+}
+
+async fn nop() {}
+
+async fn real_main() {
+    nop().await;
+    nop().await;
+    nop().await;
+    nop().await;
+
+    let mut map: HashMap<(), ()> = HashMap::new();
+    map.insert((), nop().await);
+}
index 64fb6280dd7bb644bc62a8ff8ab82759a5ed747f..daee8469a1406fce5850d94f9e645d1a28faf0f4 100644 (file)
@@ -1,6 +1,8 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // build-pass
 // edition:2018
-// compile-flags: -Zdrop-tracking=y
 
 fn main() {
     let _ = foo();
index fa3f3303677daa204b6f607faa962a8f4301ca1c..e520dfbdccebba4c062457d42fb90c4289eee686 100644 (file)
@@ -1,5 +1,7 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2021
-// compile-flags: -Zdrop-tracking
 // build-pass
 
 struct A;
diff --git a/tests/ui/async-await/drop-track-field-assign-nonsend.drop_tracking.stderr b/tests/ui/async-await/drop-track-field-assign-nonsend.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..e2bba81
--- /dev/null
@@ -0,0 +1,25 @@
+error: future cannot be sent between threads safely
+  --> $DIR/drop-track-field-assign-nonsend.rs:45:17
+   |
+LL |     assert_send(agent.handle());
+   |                 ^^^^^^^^^^^^^^ future returned by `handle` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/drop-track-field-assign-nonsend.rs:23:38
+   |
+LL |         let mut info = self.info_result.clone();
+   |             -------- has type `InfoResult` which is not `Send`
+...
+LL |         let _ = send_element(element).await;
+   |                                      ^^^^^^ await occurs here, with `mut info` maybe used later
+LL |     }
+   |     - `mut info` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/drop-track-field-assign-nonsend.rs:40:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/drop-track-field-assign-nonsend.drop_tracking_mir.stderr b/tests/ui/async-await/drop-track-field-assign-nonsend.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..b89d868
--- /dev/null
@@ -0,0 +1,23 @@
+error: future cannot be sent between threads safely
+  --> $DIR/drop-track-field-assign-nonsend.rs:45:17
+   |
+LL |     assert_send(agent.handle());
+   |                 ^^^^^^^^^^^^^^ future returned by `handle` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/drop-track-field-assign-nonsend.rs:23:38
+   |
+LL |         let mut info = self.info_result.clone();
+   |             -------- has type `InfoResult` which is not `Send`
+...
+LL |         let _ = send_element(element).await;
+   |                                      ^^^^^^ await occurs here, with `mut info` maybe used later
+note: required by a bound in `assert_send`
+  --> $DIR/drop-track-field-assign-nonsend.rs:40:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/drop-track-field-assign-nonsend.no_drop_tracking.stderr b/tests/ui/async-await/drop-track-field-assign-nonsend.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..e2bba81
--- /dev/null
@@ -0,0 +1,25 @@
+error: future cannot be sent between threads safely
+  --> $DIR/drop-track-field-assign-nonsend.rs:45:17
+   |
+LL |     assert_send(agent.handle());
+   |                 ^^^^^^^^^^^^^^ future returned by `handle` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/drop-track-field-assign-nonsend.rs:23:38
+   |
+LL |         let mut info = self.info_result.clone();
+   |             -------- has type `InfoResult` which is not `Send`
+...
+LL |         let _ = send_element(element).await;
+   |                                      ^^^^^^ await occurs here, with `mut info` maybe used later
+LL |     }
+   |     - `mut info` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/drop-track-field-assign-nonsend.rs:40:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to previous error
+
index b6c0fda15216a71ad062bb725dcc5f4b54d8ae78..3e22280008fcf251f7c6247dbccc1b8f67b00220 100644 (file)
@@ -1,6 +1,8 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // Derived from an ICE found in tokio-xmpp during a crater run.
 // edition:2021
-// compile-flags: -Zdrop-tracking
 
 #![allow(dead_code)]
 
diff --git a/tests/ui/async-await/drop-track-field-assign-nonsend.stderr b/tests/ui/async-await/drop-track-field-assign-nonsend.stderr
deleted file mode 100644 (file)
index d95483c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-error: future cannot be sent between threads safely
-  --> $DIR/drop-track-field-assign-nonsend.rs:43:17
-   |
-LL |     assert_send(agent.handle());
-   |                 ^^^^^^^^^^^^^^ future returned by `handle` is not `Send`
-   |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`
-note: future is not `Send` as this value is used across an await
-  --> $DIR/drop-track-field-assign-nonsend.rs:21:38
-   |
-LL |         let mut info = self.info_result.clone();
-   |             -------- has type `InfoResult` which is not `Send`
-...
-LL |         let _ = send_element(element).await;
-   |                                      ^^^^^^ await occurs here, with `mut info` maybe used later
-LL |     }
-   |     - `mut info` is later dropped here
-note: required by a bound in `assert_send`
-  --> $DIR/drop-track-field-assign-nonsend.rs:38:19
-   |
-LL | fn assert_send<T: Send>(_: T) {}
-   |                   ^^^^ required by this bound in `assert_send`
-
-error: aborting due to previous error
-
index 3a393cd164b9980a9423cad19bf599e4f65f551b..dd0e3f11ccc013c5fc8a5c94b9e518d08d80e09f 100644 (file)
@@ -1,6 +1,8 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // Derived from an ICE found in tokio-xmpp during a crater run.
 // edition:2021
-// compile-flags: -Zdrop-tracking
 // build-pass
 
 #![allow(dead_code)]
diff --git a/tests/ui/async-await/field-assign-nonsend.drop_tracking.stderr b/tests/ui/async-await/field-assign-nonsend.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..ac461a6
--- /dev/null
@@ -0,0 +1,25 @@
+error: future cannot be sent between threads safely
+  --> $DIR/field-assign-nonsend.rs:45:17
+   |
+LL |     assert_send(agent.handle());
+   |                 ^^^^^^^^^^^^^^ future returned by `handle` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/field-assign-nonsend.rs:23:38
+   |
+LL |         let mut info = self.info_result.clone();
+   |             -------- has type `InfoResult` which is not `Send`
+...
+LL |         let _ = send_element(element).await;
+   |                                      ^^^^^^ await occurs here, with `mut info` maybe used later
+LL |     }
+   |     - `mut info` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/field-assign-nonsend.rs:40:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/field-assign-nonsend.drop_tracking_mir.stderr b/tests/ui/async-await/field-assign-nonsend.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..8c9d14d
--- /dev/null
@@ -0,0 +1,23 @@
+error: future cannot be sent between threads safely
+  --> $DIR/field-assign-nonsend.rs:45:17
+   |
+LL |     assert_send(agent.handle());
+   |                 ^^^^^^^^^^^^^^ future returned by `handle` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/field-assign-nonsend.rs:23:38
+   |
+LL |         let mut info = self.info_result.clone();
+   |             -------- has type `InfoResult` which is not `Send`
+...
+LL |         let _ = send_element(element).await;
+   |                                      ^^^^^^ await occurs here, with `mut info` maybe used later
+note: required by a bound in `assert_send`
+  --> $DIR/field-assign-nonsend.rs:40:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/field-assign-nonsend.no_drop_tracking.stderr b/tests/ui/async-await/field-assign-nonsend.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..ac461a6
--- /dev/null
@@ -0,0 +1,25 @@
+error: future cannot be sent between threads safely
+  --> $DIR/field-assign-nonsend.rs:45:17
+   |
+LL |     assert_send(agent.handle());
+   |                 ^^^^^^^^^^^^^^ future returned by `handle` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/field-assign-nonsend.rs:23:38
+   |
+LL |         let mut info = self.info_result.clone();
+   |             -------- has type `InfoResult` which is not `Send`
+...
+LL |         let _ = send_element(element).await;
+   |                                      ^^^^^^ await occurs here, with `mut info` maybe used later
+LL |     }
+   |     - `mut info` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/field-assign-nonsend.rs:40:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/field-assign-nonsend.rs b/tests/ui/async-await/field-assign-nonsend.rs
new file mode 100644 (file)
index 0000000..3e22280
--- /dev/null
@@ -0,0 +1,47 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+// Derived from an ICE found in tokio-xmpp during a crater run.
+// edition:2021
+
+#![allow(dead_code)]
+
+#[derive(Clone)]
+struct InfoResult {
+    node: Option<std::rc::Rc<String>>
+}
+
+struct Agent {
+    info_result: InfoResult
+}
+
+impl Agent {
+    async fn handle(&mut self) {
+        let mut info = self.info_result.clone();
+        info.node = None;
+        let element = parse_info(info);
+        let _ = send_element(element).await;
+    }
+}
+
+struct Element {
+}
+
+async fn send_element(_: Element) {}
+
+fn parse(_: &[u8]) -> Result<(), ()> {
+    Ok(())
+}
+
+fn parse_info(_: InfoResult) -> Element {
+    Element { }
+}
+
+fn assert_send<T: Send>(_: T) {}
+
+fn main() {
+    let agent = Agent { info_result: InfoResult { node: None } };
+    // FIXME: It would be nice for this to work. See #94067.
+    assert_send(agent.handle());
+    //~^ cannot be sent between threads safely
+}
diff --git a/tests/ui/async-await/field-assign.rs b/tests/ui/async-await/field-assign.rs
new file mode 100644 (file)
index 0000000..dd0e3f1
--- /dev/null
@@ -0,0 +1,46 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+// Derived from an ICE found in tokio-xmpp during a crater run.
+// edition:2021
+// build-pass
+
+#![allow(dead_code)]
+
+#[derive(Clone)]
+struct InfoResult {
+    node: Option<String>
+}
+
+struct Agent {
+    info_result: InfoResult
+}
+
+impl Agent {
+    async fn handle(&mut self) {
+        let mut info = self.info_result.clone();
+        info.node = Some("bar".into());
+        let element = parse_info(info);
+        let _ = send_element(element).await;
+    }
+}
+
+struct Element {
+}
+
+async fn send_element(_: Element) {}
+
+fn parse(_: &[u8]) -> Result<(), ()> {
+    Ok(())
+}
+
+fn parse_info(_: InfoResult) -> Element {
+    Element { }
+}
+
+fn main() {
+    let mut agent = Agent {
+        info_result: InfoResult { node: None }
+    };
+    let _ = agent.handle();
+}
diff --git a/tests/ui/async-await/in-trait/missing-send-bound.rs b/tests/ui/async-await/in-trait/missing-send-bound.rs
new file mode 100644 (file)
index 0000000..78922b5
--- /dev/null
@@ -0,0 +1,21 @@
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+
+trait Foo {
+    async fn bar();
+}
+
+async fn test<T: Foo>() {
+    T::bar().await;
+}
+
+fn test2<T: Foo>() {
+    assert_is_send(test::<T>());
+    //~^ ERROR future cannot be sent between threads safely
+}
+
+fn assert_is_send(_: impl Send) {}
+
+fn main() {}
diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.stderr
new file mode 100644 (file)
index 0000000..5cedf3d
--- /dev/null
@@ -0,0 +1,29 @@
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/missing-send-bound.rs:3:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: future cannot be sent between threads safely
+  --> $DIR/missing-send-bound.rs:15:20
+   |
+LL |     assert_is_send(test::<T>());
+   |                    ^^^^^^^^^^^ future returned by `test` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>`
+note: future is not `Send` as it awaits another future which is not `Send`
+  --> $DIR/missing-send-bound.rs:11:5
+   |
+LL |     T::bar().await;
+   |     ^^^^^^^^ await occurs here on type `impl Future<Output = ()>`, which is not `Send`
+note: required by a bound in `assert_is_send`
+  --> $DIR/missing-send-bound.rs:19:27
+   |
+LL | fn assert_is_send(_: impl Send) {}
+   |                           ^^^^ required by this bound in `assert_is_send`
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/ui/async-await/issue-107036.rs b/tests/ui/async-await/issue-107036.rs
new file mode 100644 (file)
index 0000000..6a22de2
--- /dev/null
@@ -0,0 +1,14 @@
+// aux-build:issue-107036.rs
+// edition:2021
+// check-pass
+
+extern crate issue_107036;
+use issue_107036::S;
+
+async fn f() {
+    S{}.f().await;
+}
+
+fn main() {
+    let _ = f();
+}
diff --git a/tests/ui/async-await/issue-64130-1-sync.drop_tracking.stderr b/tests/ui/async-await/issue-64130-1-sync.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..c4c7f26
--- /dev/null
@@ -0,0 +1,25 @@
+error: future cannot be shared between threads safely
+  --> $DIR/issue-64130-1-sync.rs:25:13
+   |
+LL |     is_sync(bar());
+   |             ^^^^^ future returned by `bar` is not `Sync`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo`
+note: future is not `Sync` as this value is used across an await
+  --> $DIR/issue-64130-1-sync.rs:18:10
+   |
+LL |     let x = Foo;
+   |         - has type `Foo` which is not `Sync`
+LL |     baz().await;
+   |          ^^^^^^ await occurs here, with `x` maybe used later
+LL |     drop(x);
+LL | }
+   | - `x` is later dropped here
+note: required by a bound in `is_sync`
+  --> $DIR/issue-64130-1-sync.rs:14:15
+   |
+LL | fn is_sync<T: Sync>(t: T) { }
+   |               ^^^^ required by this bound in `is_sync`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/issue-64130-1-sync.drop_tracking_mir.stderr b/tests/ui/async-await/issue-64130-1-sync.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..6f43b56
--- /dev/null
@@ -0,0 +1,22 @@
+error: future cannot be shared between threads safely
+  --> $DIR/issue-64130-1-sync.rs:25:13
+   |
+LL |     is_sync(bar());
+   |             ^^^^^ future returned by `bar` is not `Sync`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo`
+note: future is not `Sync` as this value is used across an await
+  --> $DIR/issue-64130-1-sync.rs:18:10
+   |
+LL |     let x = Foo;
+   |         - has type `Foo` which is not `Sync`
+LL |     baz().await;
+   |          ^^^^^^ await occurs here, with `x` maybe used later
+note: required by a bound in `is_sync`
+  --> $DIR/issue-64130-1-sync.rs:14:15
+   |
+LL | fn is_sync<T: Sync>(t: T) { }
+   |               ^^^^ required by this bound in `is_sync`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/issue-64130-1-sync.no_drop_tracking.stderr b/tests/ui/async-await/issue-64130-1-sync.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..c4c7f26
--- /dev/null
@@ -0,0 +1,25 @@
+error: future cannot be shared between threads safely
+  --> $DIR/issue-64130-1-sync.rs:25:13
+   |
+LL |     is_sync(bar());
+   |             ^^^^^ future returned by `bar` is not `Sync`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo`
+note: future is not `Sync` as this value is used across an await
+  --> $DIR/issue-64130-1-sync.rs:18:10
+   |
+LL |     let x = Foo;
+   |         - has type `Foo` which is not `Sync`
+LL |     baz().await;
+   |          ^^^^^^ await occurs here, with `x` maybe used later
+LL |     drop(x);
+LL | }
+   | - `x` is later dropped here
+note: required by a bound in `is_sync`
+  --> $DIR/issue-64130-1-sync.rs:14:15
+   |
+LL | fn is_sync<T: Sync>(t: T) { }
+   |               ^^^^ required by this bound in `is_sync`
+
+error: aborting due to previous error
+
index 1714cec5221de4e8cdeb6b9819f31d25dc8c9d64..44646e0e5f27be0c911ac795e76a97201c9e47d8 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 #![feature(negative_impls)]
 // edition:2018
 
@@ -13,6 +16,7 @@ fn is_sync<T: Sync>(t: T) { }
 async fn bar() {
     let x = Foo;
     baz().await;
+    drop(x);
 }
 
 async fn baz() { }
index e205de4738f24c3ebac12fd79d0d12c27e2ae625..8d5169a6302eea0afeec7e746712b17b2d24661c 100644 (file)
@@ -1,12 +1,12 @@
 error: future cannot be shared between threads safely
-  --> $DIR/issue-64130-1-sync.rs:21:13
+  --> $DIR/issue-64130-1-sync.rs:24:13
    |
 LL |     is_sync(bar());
    |             ^^^^^ future returned by `bar` is not `Sync`
    |
    = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo`
 note: future is not `Sync` as this value is used across an await
-  --> $DIR/issue-64130-1-sync.rs:15:10
+  --> $DIR/issue-64130-1-sync.rs:18:10
    |
 LL |     let x = Foo;
    |         - has type `Foo` which is not `Sync`
@@ -15,7 +15,7 @@ LL |     baz().await;
 LL | }
    | - `x` is later dropped here
 note: required by a bound in `is_sync`
-  --> $DIR/issue-64130-1-sync.rs:11:15
+  --> $DIR/issue-64130-1-sync.rs:14:15
    |
 LL | fn is_sync<T: Sync>(t: T) { }
    |               ^^^^ required by this bound in `is_sync`
diff --git a/tests/ui/async-await/issue-64130-2-send.drop_tracking.stderr b/tests/ui/async-await/issue-64130-2-send.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..b6a73c2
--- /dev/null
@@ -0,0 +1,28 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-64130-2-send.rs:24:13
+   |
+LL |     is_send(bar());
+   |             ^^^^^ future returned by `bar` is not `Send`
+   |
+   = note: the trait bound `Unique<Foo>: Send` is not satisfied
+note: future is not `Send` as this value is used across an await
+  --> $DIR/issue-64130-2-send.rs:18:10
+   |
+LL |     let x = Box::new(Foo);
+   |         - has type `Box<Foo>` which is not `Send`
+LL |     baz().await;
+   |          ^^^^^^ await occurs here, with `x` maybe used later
+LL | }
+   | - `x` is later dropped here
+note: required by a bound in `is_send`
+  --> $DIR/issue-64130-2-send.rs:14:15
+   |
+LL | fn is_send<T: Send>(t: T) { }
+   |               ^^^^ required by this bound in `is_send`
+help: consider borrowing here
+   |
+LL |     is_send(&bar());
+   |             +
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/issue-64130-2-send.drop_tracking_mir.stderr b/tests/ui/async-await/issue-64130-2-send.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..560560f
--- /dev/null
@@ -0,0 +1,26 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-64130-2-send.rs:24:13
+   |
+LL |     is_send(bar());
+   |             ^^^^^ future returned by `bar` is not `Send`
+   |
+   = note: the trait bound `Unique<Foo>: Send` is not satisfied
+note: future is not `Send` as this value is used across an await
+  --> $DIR/issue-64130-2-send.rs:18:10
+   |
+LL |     let x = Box::new(Foo);
+   |         - has type `Box<Foo>` which is not `Send`
+LL |     baz().await;
+   |          ^^^^^^ await occurs here, with `x` maybe used later
+note: required by a bound in `is_send`
+  --> $DIR/issue-64130-2-send.rs:14:15
+   |
+LL | fn is_send<T: Send>(t: T) { }
+   |               ^^^^ required by this bound in `is_send`
+help: consider borrowing here
+   |
+LL |     is_send(&bar());
+   |             +
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/issue-64130-2-send.no_drop_tracking.stderr b/tests/ui/async-await/issue-64130-2-send.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..b6a73c2
--- /dev/null
@@ -0,0 +1,28 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-64130-2-send.rs:24:13
+   |
+LL |     is_send(bar());
+   |             ^^^^^ future returned by `bar` is not `Send`
+   |
+   = note: the trait bound `Unique<Foo>: Send` is not satisfied
+note: future is not `Send` as this value is used across an await
+  --> $DIR/issue-64130-2-send.rs:18:10
+   |
+LL |     let x = Box::new(Foo);
+   |         - has type `Box<Foo>` which is not `Send`
+LL |     baz().await;
+   |          ^^^^^^ await occurs here, with `x` maybe used later
+LL | }
+   | - `x` is later dropped here
+note: required by a bound in `is_send`
+  --> $DIR/issue-64130-2-send.rs:14:15
+   |
+LL | fn is_send<T: Send>(t: T) { }
+   |               ^^^^ required by this bound in `is_send`
+help: consider borrowing here
+   |
+LL |     is_send(&bar());
+   |             +
+
+error: aborting due to previous error
+
index 7a6e5952cb956df7bfed253cb716c31dd01bec01..d6d855bac0762b4dddc5bc68fc29b5dcbead4e48 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 #![feature(negative_impls)]
 // edition:2018
 
@@ -11,7 +14,7 @@ impl !Send for Foo {}
 fn is_send<T: Send>(t: T) { }
 
 async fn bar() {
-    let x = Foo;
+    let x = Box::new(Foo);
     baz().await;
 }
 
index 2225000e2e5797c6383d1c636fdec7de1147ff0b..f6505cad69e21236a093873947d39d3c16d5b5d5 100644 (file)
@@ -1,12 +1,12 @@
 error: future cannot be sent between threads safely
-  --> $DIR/issue-64130-2-send.rs:21:13
+  --> $DIR/issue-64130-2-send.rs:24:13
    |
 LL |     is_send(bar());
    |             ^^^^^ future returned by `bar` is not `Send`
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Foo`
 note: future is not `Send` as this value is used across an await
-  --> $DIR/issue-64130-2-send.rs:15:10
+  --> $DIR/issue-64130-2-send.rs:18:10
    |
 LL |     let x = Foo;
    |         - has type `Foo` which is not `Send`
@@ -15,7 +15,7 @@ LL |     baz().await;
 LL | }
    | - `x` is later dropped here
 note: required by a bound in `is_send`
-  --> $DIR/issue-64130-2-send.rs:11:15
+  --> $DIR/issue-64130-2-send.rs:14:15
    |
 LL | fn is_send<T: Send>(t: T) { }
    |               ^^^^ required by this bound in `is_send`
diff --git a/tests/ui/async-await/issue-64130-3-other.drop_tracking.stderr b/tests/ui/async-await/issue-64130-3-other.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..d65aae8
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>`
+  --> $DIR/issue-64130-3-other.rs:27:12
+   |
+LL | async fn bar() {
+   |                - within this `impl Future<Output = ()>`
+...
+LL |     is_qux(bar());
+   |            ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo`
+   |
+note: future does not implement `Qux` as this value is used across an await
+  --> $DIR/issue-64130-3-other.rs:21:10
+   |
+LL |     let x = Box::new(Foo);
+   |         - has type `Box<Foo>` which does not implement `Qux`
+LL |     baz().await;
+   |          ^^^^^^ await occurs here, with `x` maybe used later
+LL | }
+   | - `x` is later dropped here
+note: required by a bound in `is_qux`
+  --> $DIR/issue-64130-3-other.rs:17:14
+   |
+LL | fn is_qux<T: Qux>(t: T) {}
+   |              ^^^ required by this bound in `is_qux`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/issue-64130-3-other.drop_tracking_mir.stderr b/tests/ui/async-await/issue-64130-3-other.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..8fed69d
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>`
+  --> $DIR/issue-64130-3-other.rs:27:12
+   |
+LL | async fn bar() {
+   |                - within this `impl Future<Output = ()>`
+...
+LL |     is_qux(bar());
+   |            ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo`
+   |
+note: future does not implement `Qux` as this value is used across an await
+  --> $DIR/issue-64130-3-other.rs:21:10
+   |
+LL |     let x = Box::new(Foo);
+   |         - has type `Box<Foo>` which does not implement `Qux`
+LL |     baz().await;
+   |          ^^^^^^ await occurs here, with `x` maybe used later
+note: required by a bound in `is_qux`
+  --> $DIR/issue-64130-3-other.rs:17:14
+   |
+LL | fn is_qux<T: Qux>(t: T) {}
+   |              ^^^ required by this bound in `is_qux`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/issue-64130-3-other.no_drop_tracking.stderr b/tests/ui/async-await/issue-64130-3-other.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..d65aae8
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>`
+  --> $DIR/issue-64130-3-other.rs:27:12
+   |
+LL | async fn bar() {
+   |                - within this `impl Future<Output = ()>`
+...
+LL |     is_qux(bar());
+   |            ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo`
+   |
+note: future does not implement `Qux` as this value is used across an await
+  --> $DIR/issue-64130-3-other.rs:21:10
+   |
+LL |     let x = Box::new(Foo);
+   |         - has type `Box<Foo>` which does not implement `Qux`
+LL |     baz().await;
+   |          ^^^^^^ await occurs here, with `x` maybe used later
+LL | }
+   | - `x` is later dropped here
+note: required by a bound in `is_qux`
+  --> $DIR/issue-64130-3-other.rs:17:14
+   |
+LL | fn is_qux<T: Qux>(t: T) {}
+   |              ^^^ required by this bound in `is_qux`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 630fb2c41cded629a7d0c6eb9c452988a6e2632d..92d3b7c81fb62e8ec1de472de5aaa3059762a647 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 #![feature(auto_traits)]
 #![feature(negative_impls)]
 // edition:2018
@@ -14,7 +17,7 @@ impl !Qux for Foo {}
 fn is_qux<T: Qux>(t: T) {}
 
 async fn bar() {
-    let x = Foo;
+    let x = Box::new(Foo);
     baz().await;
 }
 
index 17867a6a3f62e6b6fc48f646a2967d89cc7b96ea..cb36a3811b2803eb5fe1ed98875321716c4fbaa6 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>`
-  --> $DIR/issue-64130-3-other.rs:24:12
+  --> $DIR/issue-64130-3-other.rs:27:12
    |
 LL | async fn bar() {
    |                - within this `impl Future<Output = ()>`
@@ -8,7 +8,7 @@ LL |     is_qux(bar());
    |            ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo`
    |
 note: future does not implement `Qux` as this value is used across an await
-  --> $DIR/issue-64130-3-other.rs:18:10
+  --> $DIR/issue-64130-3-other.rs:21:10
    |
 LL |     let x = Foo;
    |         - has type `Foo` which does not implement `Qux`
@@ -17,7 +17,7 @@ LL |     baz().await;
 LL | }
    | - `x` is later dropped here
 note: required by a bound in `is_qux`
-  --> $DIR/issue-64130-3-other.rs:14:14
+  --> $DIR/issue-64130-3-other.rs:17:14
    |
 LL | fn is_qux<T: Qux>(t: T) {}
    |              ^^^ required by this bound in `is_qux`
index f609e36362c440e0e8b5d87995d40027e39f2e19..884619f4dd69d4151a9c79a1bc401789173e29a9 100644 (file)
@@ -1,12 +1,12 @@
 error: future cannot be sent between threads safely
-  --> $DIR/issue-64130-4-async-move.rs:19:17
+  --> $DIR/issue-64130-4-async-move.rs:20:17
    |
 LL | pub fn foo() -> impl Future + Send {
    |                 ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
    |
    = help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)`
 note: future is not `Send` as this value is used across an await
-  --> $DIR/issue-64130-4-async-move.rs:25:31
+  --> $DIR/issue-64130-4-async-move.rs:27:31
    |
 LL |         match client.status() {
    |               ------ has type `&Client` which is not `Send`
@@ -17,7 +17,7 @@ LL |                 let _x = get().await;
 LL |     }
    |     - `client` is later dropped here
 help: consider moving this into a `let` binding to create a shorter lived borrow
-  --> $DIR/issue-64130-4-async-move.rs:23:15
+  --> $DIR/issue-64130-4-async-move.rs:25:15
    |
 LL |         match client.status() {
    |               ^^^^^^^^^^^^^^^
index f609e36362c440e0e8b5d87995d40027e39f2e19..0bc7cb2f2acdab035f7a1d13a16ae44f2339432d 100644 (file)
@@ -1,12 +1,12 @@
 error: future cannot be sent between threads safely
-  --> $DIR/issue-64130-4-async-move.rs:19:17
+  --> $DIR/issue-64130-4-async-move.rs:21:17
    |
 LL | pub fn foo() -> impl Future + Send {
    |                 ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
    |
    = help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)`
 note: future is not `Send` as this value is used across an await
-  --> $DIR/issue-64130-4-async-move.rs:25:31
+  --> $DIR/issue-64130-4-async-move.rs:27:31
    |
 LL |         match client.status() {
    |               ------ has type `&Client` which is not `Send`
@@ -17,7 +17,7 @@ LL |                 let _x = get().await;
 LL |     }
    |     - `client` is later dropped here
 help: consider moving this into a `let` binding to create a shorter lived borrow
-  --> $DIR/issue-64130-4-async-move.rs:23:15
+  --> $DIR/issue-64130-4-async-move.rs:25:15
    |
 LL |         match client.status() {
    |               ^^^^^^^^^^^^^^^
index a38428fc00f0bb63be5c6cda36ef22f81cc10536..bcb297aaa02585a994f8be3869c447f0fb0291fa 100644 (file)
@@ -1,8 +1,10 @@
 // edition:2018
-// revisions: no_drop_tracking drop_tracking
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+// [drop_tracking_mir] check-pass
 // [drop_tracking] check-pass
-// [drop_tracking] compile-flags: -Zdrop-tracking=yes
-// [no_drop_tracking] compile-flags: -Zdrop-tracking=no
+
 use std::any::Any;
 use std::future::Future;
 
diff --git a/tests/ui/async-await/issue-67252-unnamed-future.drop_tracking.stderr b/tests/ui/async-await/issue-67252-unnamed-future.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..fc8bcc8
--- /dev/null
@@ -0,0 +1,30 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-67252-unnamed-future.rs:21:11
+   |
+LL |       spawn(async {
+   |  ___________^
+LL | |         let a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send`
+LL | |         AFuture.await;
+LL | |         drop(a);
+LL | |     });
+   | |_____^ future created by async block is not `Send`
+   |
+   = help: within `[async block@$DIR/issue-67252-unnamed-future.rs:21:11: 25:6]`, the trait `Send` is not implemented for `*mut ()`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/issue-67252-unnamed-future.rs:23:16
+   |
+LL |         let a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send`
+   |             - has type `*mut ()` which is not `Send`
+LL |         AFuture.await;
+   |                ^^^^^^ await occurs here, with `a` maybe used later
+LL |         drop(a);
+LL |     });
+   |     - `a` is later dropped here
+note: required by a bound in `spawn`
+  --> $DIR/issue-67252-unnamed-future.rs:9:13
+   |
+LL | fn spawn<T: Send>(_: T) {}
+   |             ^^^^ required by this bound in `spawn`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/issue-67252-unnamed-future.drop_tracking_mir.stderr b/tests/ui/async-await/issue-67252-unnamed-future.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..a3ef7ad
--- /dev/null
@@ -0,0 +1,22 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-67252-unnamed-future.rs:21:5
+   |
+LL |     spawn(async {
+   |     ^^^^^ future created by async block is not `Send`
+   |
+   = help: within `[async block@$DIR/issue-67252-unnamed-future.rs:21:11: 25:6]`, the trait `Send` is not implemented for `*mut ()`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/issue-67252-unnamed-future.rs:23:16
+   |
+LL |         let a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send`
+   |             - has type `*mut ()` which is not `Send`
+LL |         AFuture.await;
+   |                ^^^^^^ await occurs here, with `a` maybe used later
+note: required by a bound in `spawn`
+  --> $DIR/issue-67252-unnamed-future.rs:9:13
+   |
+LL | fn spawn<T: Send>(_: T) {}
+   |             ^^^^ required by this bound in `spawn`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/issue-67252-unnamed-future.no_drop_tracking.stderr b/tests/ui/async-await/issue-67252-unnamed-future.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..fc8bcc8
--- /dev/null
@@ -0,0 +1,30 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-67252-unnamed-future.rs:21:11
+   |
+LL |       spawn(async {
+   |  ___________^
+LL | |         let a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send`
+LL | |         AFuture.await;
+LL | |         drop(a);
+LL | |     });
+   | |_____^ future created by async block is not `Send`
+   |
+   = help: within `[async block@$DIR/issue-67252-unnamed-future.rs:21:11: 25:6]`, the trait `Send` is not implemented for `*mut ()`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/issue-67252-unnamed-future.rs:23:16
+   |
+LL |         let a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send`
+   |             - has type `*mut ()` which is not `Send`
+LL |         AFuture.await;
+   |                ^^^^^^ await occurs here, with `a` maybe used later
+LL |         drop(a);
+LL |     });
+   |     - `a` is later dropped here
+note: required by a bound in `spawn`
+  --> $DIR/issue-67252-unnamed-future.rs:9:13
+   |
+LL | fn spawn<T: Send>(_: T) {}
+   |             ^^^^ required by this bound in `spawn`
+
+error: aborting due to previous error
+
index 1a7ff613341ece66d7d2097028ccd642abfcf6fc..bb9ad77cef31daf001ae185a8f488ad13e8aaf96 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2018
 use std::future::Future;
 use std::pin::Pin;
@@ -16,8 +19,9 @@ fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<()> {
 
 async fn foo() {
     spawn(async { //~ ERROR future cannot be sent between threads safely
-        let _a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send`
+        let a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send`
         AFuture.await;
+        drop(a);
     });
 }
 
diff --git a/tests/ui/async-await/issue-67252-unnamed-future.stderr b/tests/ui/async-await/issue-67252-unnamed-future.stderr
deleted file mode 100644 (file)
index fcba441..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-error: future cannot be sent between threads safely
-  --> $DIR/issue-67252-unnamed-future.rs:18:11
-   |
-LL |       spawn(async {
-   |  ___________^
-LL | |         let _a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send`
-LL | |         AFuture.await;
-LL | |     });
-   | |_____^ future created by async block is not `Send`
-   |
-   = help: within `[async block@$DIR/issue-67252-unnamed-future.rs:18:11: 21:6]`, the trait `Send` is not implemented for `*mut ()`
-note: future is not `Send` as this value is used across an await
-  --> $DIR/issue-67252-unnamed-future.rs:20:16
-   |
-LL |         let _a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send`
-   |             -- has type `*mut ()` which is not `Send`
-LL |         AFuture.await;
-   |                ^^^^^^ await occurs here, with `_a` maybe used later
-LL |     });
-   |     - `_a` is later dropped here
-note: required by a bound in `spawn`
-  --> $DIR/issue-67252-unnamed-future.rs:6:13
-   |
-LL | fn spawn<T: Send>(_: T) {}
-   |             ^^^^ required by this bound in `spawn`
-
-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
diff --git a/tests/ui/async-await/issue-68112.drop_tracking_mir.stderr b/tests/ui/async-await/issue-68112.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..7a9242c
--- /dev/null
@@ -0,0 +1,80 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-68112.rs:37:5
+   |
+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
+   |
+LL |         let _ = non_send_fut.await;
+   |                 ^^^^^^^^^^^^ await occurs here on type `impl Future<Output = Arc<RefCell<i32>>>`, which is not `Send`
+note: required by a bound in `require_send`
+  --> $DIR/issue-68112.rs:14:25
+   |
+LL | fn require_send(_: impl Send) {}
+   |                         ^^^^ required by this bound in `require_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/issue-68112.rs:46:5
+   |
+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
+   |
+LL |         let _ = make_non_send_future1().await;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl Future<Output = Arc<RefCell<i32>>>`, which is not `Send`
+note: required by a bound in `require_send`
+  --> $DIR/issue-68112.rs:14:25
+   |
+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:65:5
+   |
+LL |     require_send(send_fut);
+   |     ^^^^^^^^^^^^ `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 for `Arc<RefCell<i32>>` to implement `Send`
+note: required because it's used within this `async fn` body
+  --> $DIR/issue-68112.rs:50:31
+   |
+LL |   async fn ready2<T>(t: T) -> T {
+   |  _______________________________^
+LL | |     t
+LL | | }
+   | |_^
+note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
+  --> $DIR/issue-68112.rs:53:31
+   |
+LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> {
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: required because it captures the following types: `impl Future<Output = Arc<RefCell<i32>>>`, `Ready<i32>`
+note: required because it's used within this `async` block
+  --> $DIR/issue-68112.rs:60:20
+   |
+LL |       let send_fut = async {
+   |  ____________________^
+LL | |         let non_send_fut = make_non_send_future2();
+LL | |         let _ = non_send_fut.await;
+LL | |         ready(0).await;
+LL | |     };
+   | |_____^
+note: required by a bound in `require_send`
+  --> $DIR/issue-68112.rs:14:25
+   |
+LL | fn require_send(_: impl Send) {}
+   |                         ^^^^ required by this bound in `require_send`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
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 9c705137a10564580ae16023f193c355ee6672d5..19119ae0fc127669a978cc3c5da39294e8edcce9 100644 (file)
@@ -1,7 +1,7 @@
 // edition:2018
-// revisions: no_drop_tracking drop_tracking
-// [drop_tracking] compile-flags: -Zdrop-tracking=yes
-// [no_drop_tracking] compile-flags: -Zdrop-tracking=no
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 
 use std::{
     cell::RefCell,
@@ -14,7 +14,7 @@
 fn require_send(_: impl Send) {}
 
 struct Ready<T>(Option<T>);
-impl<T> Future for Ready<T> {
+impl<T: Unpin> Future for Ready<T> {
     type Output = T;
     fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<T> {
         Poll::Ready(self.0.take().unwrap())
diff --git a/tests/ui/async-await/issue-70818.drop_tracking.stderr b/tests/ui/async-await/issue-70818.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..ab0698c
--- /dev/null
@@ -0,0 +1,18 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-70818.rs:7:38
+   |
+LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
+   |
+note: captured value is not `Send`
+  --> $DIR/issue-70818.rs:9:18
+   |
+LL |     async { (ty, ty1) }
+   |                  ^^^ has type `U` which is not `Send`
+help: consider restricting type parameter `U`
+   |
+LL | fn foo<T: Send, U: std::marker::Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
+   |                  +++++++++++++++++++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/issue-70818.drop_tracking_mir.stderr b/tests/ui/async-await/issue-70818.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..ab0698c
--- /dev/null
@@ -0,0 +1,18 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-70818.rs:7:38
+   |
+LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
+   |
+note: captured value is not `Send`
+  --> $DIR/issue-70818.rs:9:18
+   |
+LL |     async { (ty, ty1) }
+   |                  ^^^ has type `U` which is not `Send`
+help: consider restricting type parameter `U`
+   |
+LL | fn foo<T: Send, U: std::marker::Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
+   |                  +++++++++++++++++++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/issue-70818.no_drop_tracking.stderr b/tests/ui/async-await/issue-70818.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..ab0698c
--- /dev/null
@@ -0,0 +1,18 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-70818.rs:7:38
+   |
+LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
+   |
+note: captured value is not `Send`
+  --> $DIR/issue-70818.rs:9:18
+   |
+LL |     async { (ty, ty1) }
+   |                  ^^^ has type `U` which is not `Send`
+help: consider restricting type parameter `U`
+   |
+LL | fn foo<T: Send, U: std::marker::Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
+   |                  +++++++++++++++++++
+
+error: aborting due to previous error
+
index 019c56eb2fa3efc2329396f1fc13f90e20722d25..2941de0f57714cb36ff363c2033057617b8af6d2 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2018
 
 use std::future::Future;
index 20109d4d1166a0e3331d4289ef60d2628ae1b1d9..ab0698c3ec2132dc9c8def966e733d938f8b8145 100644 (file)
@@ -1,11 +1,11 @@
 error: future cannot be sent between threads safely
-  --> $DIR/issue-70818.rs:4:38
+  --> $DIR/issue-70818.rs:7:38
    |
 LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
    |
 note: captured value is not `Send`
-  --> $DIR/issue-70818.rs:6:18
+  --> $DIR/issue-70818.rs:9:18
    |
 LL |     async { (ty, ty1) }
    |                  ^^^ has type `U` which is not `Send`
diff --git a/tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr b/tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..c636be1
--- /dev/null
@@ -0,0 +1,34 @@
+error[E0277]: `Sender<i32>` cannot be shared between threads safely
+  --> $DIR/issue-70935-complex-spans.rs:13:45
+   |
+LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
+   |                                             ^^^^^^^^^^^^^^^^^^ `Sender<i32>` cannot be shared between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `Sender<i32>`
+   = note: required for `&Sender<i32>` to implement `Send`
+note: required because it's used within this closure
+  --> $DIR/issue-70935-complex-spans.rs:17:13
+   |
+LL |         baz(|| async{
+   |             ^^
+note: required because it's used within this `async fn` body
+  --> $DIR/issue-70935-complex-spans.rs:10:67
+   |
+LL |   async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
+   |  ___________________________________________________________________^
+LL | | }
+   | |_^
+   = note: required because it captures the following types: `impl Future<Output = ()>`
+note: required because it's used within this `async` block
+  --> $DIR/issue-70935-complex-spans.rs:16:5
+   |
+LL | /     async move {
+LL | |         baz(|| async{
+LL | |             foo(tx.clone());
+LL | |         }).await;
+LL | |     }
+   | |_____^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index b6d17f93a6675119914d4467741fea2fbcac046e..78625bd393d25f9fba5651bd18c534878a19c57b 100644 (file)
@@ -1,7 +1,7 @@
 // edition:2018
-// revisions: no_drop_tracking drop_tracking
-// [no_drop_tracking]compile-flags:-Zdrop-tracking=no
-// [drop_tracking]compile-flags:-Zdrop-tracking
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // #70935: Check if we do not emit snippet
 // with newlines which lead complex diagnostics.
 
@@ -12,7 +12,7 @@ async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
 
 fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
     //[no_drop_tracking]~^ ERROR future cannot be sent between threads safely
-    //[drop_tracking]~^^ ERROR `Sender<i32>` cannot be shared between threads
+    //[drop_tracking,drop_tracking_mir]~^^ ERROR `Sender<i32>` cannot be shared between threads
     async move {
         baz(|| async{
             foo(tx.clone());
diff --git a/tests/ui/async-await/issue-73741-type-err-drop-tracking.drop_tracking.stderr b/tests/ui/async-await/issue-73741-type-err-drop-tracking.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..6d19c3b
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/issue-73741-type-err-drop-tracking.rs:11:7
+   |
+LL |     1 = 2;
+   |     - ^
+   |     |
+   |     cannot assign to this expression
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0070`.
diff --git a/tests/ui/async-await/issue-73741-type-err-drop-tracking.drop_tracking_mir.stderr b/tests/ui/async-await/issue-73741-type-err-drop-tracking.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..6d19c3b
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/issue-73741-type-err-drop-tracking.rs:11:7
+   |
+LL |     1 = 2;
+   |     - ^
+   |     |
+   |     cannot assign to this expression
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0070`.
diff --git a/tests/ui/async-await/issue-73741-type-err-drop-tracking.no_drop_tracking.stderr b/tests/ui/async-await/issue-73741-type-err-drop-tracking.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..6d19c3b
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/issue-73741-type-err-drop-tracking.rs:11:7
+   |
+LL |     1 = 2;
+   |     - ^
+   |     |
+   |     cannot assign to this expression
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0070`.
index c3423ad629f166f60b14f4a00d28aab4f04eeb7b..1fa8d69143a22ce9ac462e5d27f54fcb9cc47475 100644 (file)
@@ -1,5 +1,8 @@
 // edition:2018
-// compile-flags: -Zdrop-tracking
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+//
 // Regression test for issue #73741
 // Ensures that we don't emit spurious errors when
 // a type error ocurrs in an `async fn`
index d4e3b6c3bf40dabbf30f22200a29cc2578dbd4d5..6d19c3beb2fe12ec94570ee49cc75507c5ac91b2 100644 (file)
@@ -1,5 +1,5 @@
 error[E0070]: invalid left-hand side of assignment
-  --> $DIR/issue-73741-type-err-drop-tracking.rs:8:7
+  --> $DIR/issue-73741-type-err-drop-tracking.rs:11:7
    |
 LL |     1 = 2;
    |     - ^
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`
 
diff --git a/tests/ui/async-await/issue-86507.drop_tracking.stderr b/tests/ui/async-await/issue-86507.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..5c8b7ef
--- /dev/null
@@ -0,0 +1,23 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-86507.rs:20:13
+   |
+LL | /             Box::pin(
+LL | |                 async move {
+LL | |                     let x = x;
+LL | |                 }
+LL | |             )
+   | |_____________^ future created by async block is not `Send`
+   |
+note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
+  --> $DIR/issue-86507.rs:22:29
+   |
+LL |                     let x = x;
+   |                             ^ has type `&T` which is not `Send`, because `T` is not `Sync`
+   = note: required for the cast from `[async block@$DIR/issue-86507.rs:21:17: 23:18]` to the object type `dyn Future<Output = ()> + Send`
+help: consider further restricting this bound
+   |
+LL |     fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T)
+   |                                       +++++++++++++++++++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/issue-86507.drop_tracking_mir.stderr b/tests/ui/async-await/issue-86507.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..5c8b7ef
--- /dev/null
@@ -0,0 +1,23 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-86507.rs:20:13
+   |
+LL | /             Box::pin(
+LL | |                 async move {
+LL | |                     let x = x;
+LL | |                 }
+LL | |             )
+   | |_____________^ future created by async block is not `Send`
+   |
+note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
+  --> $DIR/issue-86507.rs:22:29
+   |
+LL |                     let x = x;
+   |                             ^ has type `&T` which is not `Send`, because `T` is not `Sync`
+   = note: required for the cast from `[async block@$DIR/issue-86507.rs:21:17: 23:18]` to the object type `dyn Future<Output = ()> + Send`
+help: consider further restricting this bound
+   |
+LL |     fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T)
+   |                                       +++++++++++++++++++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/async-await/issue-86507.no_drop_tracking.stderr b/tests/ui/async-await/issue-86507.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..5c8b7ef
--- /dev/null
@@ -0,0 +1,23 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-86507.rs:20:13
+   |
+LL | /             Box::pin(
+LL | |                 async move {
+LL | |                     let x = x;
+LL | |                 }
+LL | |             )
+   | |_____________^ future created by async block is not `Send`
+   |
+note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
+  --> $DIR/issue-86507.rs:22:29
+   |
+LL |                     let x = x;
+   |                             ^ has type `&T` which is not `Send`, because `T` is not `Sync`
+   = note: required for the cast from `[async block@$DIR/issue-86507.rs:21:17: 23:18]` to the object type `dyn Future<Output = ()> + Send`
+help: consider further restricting this bound
+   |
+LL |     fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T)
+   |                                       +++++++++++++++++++
+
+error: aborting due to previous error
+
index 317f0317664b6733f3287fb87bc5cfdad7705738..63c298dbe3dcb0ba9cae45d9f425b7b17c768883 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2018
 
 use ::core::pin::Pin;
diff --git a/tests/ui/async-await/issue-86507.stderr b/tests/ui/async-await/issue-86507.stderr
deleted file mode 100644 (file)
index 8c2c06d..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-error: future cannot be sent between threads safely
-  --> $DIR/issue-86507.rs:17:13
-   |
-LL | /             Box::pin(
-LL | |                 async move {
-LL | |                     let x = x;
-LL | |                 }
-LL | |             )
-   | |_____________^ future created by async block is not `Send`
-   |
-note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
-  --> $DIR/issue-86507.rs:19:29
-   |
-LL |                     let x = x;
-   |                             ^ has type `&T` which is not `Send`, because `T` is not `Sync`
-   = note: required for the cast from `[async block@$DIR/issue-86507.rs:18:17: 20:18]` to the object type `dyn Future<Output = ()> + Send`
-help: consider further restricting this bound
-   |
-LL |     fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T)
-   |                                       +++++++++++++++++++
-
-error: aborting due to previous error
-
index 4ce3ac1e8746030d3ff3caea1e25aa27d8d41267..ec2249ca592b586e4f18d269b7ea1158a0910184 100644 (file)
@@ -1,6 +1,8 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2021
 // build-pass
-// compile-flags: -Zdrop-tracking
 
 fn main() {
     let _ = async {
index 387966a5064fa58d329a8653f780fb0f5c450e86..d5394469806da78e7340c3b0e3b6be68e034e652 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2018
 
 use std::sync::{Arc, Mutex};
index 1033fa6cc8b344c474a9c79b6d74fdaa9eb903e9..8745bdd973beabf5637819b3d9fdc462bb7b2a61 100644 (file)
@@ -1,5 +1,5 @@
 error: future cannot be sent between threads safely
-  --> $DIR/issue-65436-raw-ptr-not-send.rs:16:17
+  --> $DIR/issue-65436-raw-ptr-not-send.rs:17:17
    |
 LL |       assert_send(async {
    |  _________________^
@@ -8,9 +8,9 @@ LL | |         bar(Foo(std::ptr::null())).await;
 LL | |     })
    | |_____^ future created by async block is not `Send`
    |
-   = help: within `[async block@$DIR/issue-65436-raw-ptr-not-send.rs:16:17: 19:6]`, the trait `Send` is not implemented for `*const u8`
+   = help: within `[async block@$DIR/issue-65436-raw-ptr-not-send.rs:17:17: 20:6]`, the trait `Send` is not implemented for `*const u8`
 note: future is not `Send` as this value is used across an await
-  --> $DIR/issue-65436-raw-ptr-not-send.rs:18:35
+  --> $DIR/issue-65436-raw-ptr-not-send.rs:19:35
    |
 LL |         bar(Foo(std::ptr::null())).await;
    |                 ----------------  ^^^^^^- `std::ptr::null()` is later dropped here
@@ -18,12 +18,12 @@ LL |         bar(Foo(std::ptr::null())).await;
    |                 |                 await occurs here, with `std::ptr::null()` maybe used later
    |                 has type `*const u8` which is not `Send`
 help: consider moving this into a `let` binding to create a shorter lived borrow
-  --> $DIR/issue-65436-raw-ptr-not-send.rs:18:13
+  --> $DIR/issue-65436-raw-ptr-not-send.rs:19:13
    |
 LL |         bar(Foo(std::ptr::null())).await;
    |             ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `assert_send`
-  --> $DIR/issue-65436-raw-ptr-not-send.rs:13:19
+  --> $DIR/issue-65436-raw-ptr-not-send.rs:14:19
    |
 LL | fn assert_send<T: Send>(_: T) {}
    |                   ^^^^ required by this bound in `assert_send`
index 91edbc10dc0d770adbf874b234f86a8d30f6e2c0..d7ef929517c74eaabfbb60f0d6ee39d4372b46e8 100644 (file)
@@ -1,8 +1,9 @@
 // edition:2018
-// revisions: no_drop_tracking drop_tracking
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // [drop_tracking] check-pass
-// [drop_tracking] compile-flags: -Zdrop-tracking=yes
-// [no_drop_tracking] compile-flags: -Zdrop-tracking=no
+// [drop_tracking_mir] check-pass
 
 struct Foo(*const u8);
 
index dda4a151dd2d60fccf0c9f035628be0016263cbe..c4f8f607d257945a7dbae674c3374d73ba156073 100644 (file)
@@ -1,6 +1,10 @@
 // build-pass
 // edition:2018
 
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+
 static mut A: [i32; 5] = [1, 2, 3, 4, 5];
 
 fn is_send_sync<T: Send + Sync>(_: T) {}
index 2ce68a782918cf064c449afedab10f6815a2f3e2..ce9424c8b252bbe78f7805755c5977c47e4df143 100644 (file)
@@ -6,7 +6,7 @@ LL |     g(issue_67893::run())
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
 note: future is not `Send` as this value is used across an await
-  --> $DIR/auxiliary/issue_67893.rs:9:26
+  --> $DIR/auxiliary/issue_67893.rs:12:26
    |
 LL |     f(*x.lock().unwrap()).await;
    |        ----------------- ^^^^^^- `x.lock().unwrap()` is later dropped here
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
diff --git a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.drop_tracking.stderr b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..8a7317b
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0733]: recursion in an `async fn` requires boxing
+  --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:18
+   |
+LL | async fn rec_1() {
+   |                  ^ recursive `async fn`
+   |
+   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error[E0733]: recursion in an `async fn` requires boxing
+  --> $DIR/mutually-recursive-async-impl-trait-type.rs:13:18
+   |
+LL | async fn rec_2() {
+   |                  ^ recursive `async fn`
+   |
+   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0733`.
diff --git a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.drop_tracking_mir.stderr b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..8a7317b
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0733]: recursion in an `async fn` requires boxing
+  --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:18
+   |
+LL | async fn rec_1() {
+   |                  ^ recursive `async fn`
+   |
+   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error[E0733]: recursion in an `async fn` requires boxing
+  --> $DIR/mutually-recursive-async-impl-trait-type.rs:13:18
+   |
+LL | async fn rec_2() {
+   |                  ^ recursive `async fn`
+   |
+   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0733`.
diff --git a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.no_drop_tracking.stderr b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..8a7317b
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0733]: recursion in an `async fn` requires boxing
+  --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:18
+   |
+LL | async fn rec_1() {
+   |                  ^ recursive `async fn`
+   |
+   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error[E0733]: recursion in an `async fn` requires boxing
+  --> $DIR/mutually-recursive-async-impl-trait-type.rs:13:18
+   |
+LL | async fn rec_2() {
+   |                  ^ recursive `async fn`
+   |
+   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0733`.
index bb2a61f03ce1f46e54d33741741df75762cda59f..a241f30e73e6eb3f7e8f9c57c669be1091adcf55 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+
 // edition:2018
 // Test that impl trait does not allow creating recursive types that are
 // otherwise forbidden when using `async` and `await`.
index f789ad2a05c7d5499b898f1f9f79c0bdee5bdc97..8a7317bb95a704682a3ccd465dada3dfc9ca8aa0 100644 (file)
@@ -1,5 +1,5 @@
 error[E0733]: recursion in an `async fn` requires boxing
-  --> $DIR/mutually-recursive-async-impl-trait-type.rs:5:18
+  --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:18
    |
 LL | async fn rec_1() {
    |                  ^ recursive `async fn`
@@ -8,7 +8,7 @@ LL | async fn rec_1() {
    = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
 
 error[E0733]: recursion in an `async fn` requires boxing
-  --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:18
+  --> $DIR/mutually-recursive-async-impl-trait-type.rs:13:18
    |
 LL | async fn rec_2() {
    |                  ^ recursive `async fn`
index a3167215dc32bc6259663a1acc5c5a665f2d3037..d4df9d439c5f15ac1638c2b5d7a9cb3d096be627 100644 (file)
@@ -1,6 +1,8 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // build-pass
 // edition:2018
-// compile-flags: -Zdrop-tracking=y
 
 #![feature(generators)]
 
diff --git a/tests/ui/async-await/recursive-async-impl-trait-type.drop_tracking.stderr b/tests/ui/async-await/recursive-async-impl-trait-type.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..7e63a8d
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0733]: recursion in an `async fn` requires boxing
+  --> $DIR/recursive-async-impl-trait-type.rs:8:40
+   |
+LL | async fn recursive_async_function() -> () {
+   |                                        ^^ recursive `async fn`
+   |
+   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0733`.
diff --git a/tests/ui/async-await/recursive-async-impl-trait-type.drop_tracking_mir.stderr b/tests/ui/async-await/recursive-async-impl-trait-type.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..7e63a8d
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0733]: recursion in an `async fn` requires boxing
+  --> $DIR/recursive-async-impl-trait-type.rs:8:40
+   |
+LL | async fn recursive_async_function() -> () {
+   |                                        ^^ recursive `async fn`
+   |
+   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0733`.
diff --git a/tests/ui/async-await/recursive-async-impl-trait-type.no_drop_tracking.stderr b/tests/ui/async-await/recursive-async-impl-trait-type.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..7e63a8d
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0733]: recursion in an `async fn` requires boxing
+  --> $DIR/recursive-async-impl-trait-type.rs:8:40
+   |
+LL | async fn recursive_async_function() -> () {
+   |                                        ^^ recursive `async fn`
+   |
+   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0733`.
index edc4cb8ac5df37153345b5a8453538bb330da90a..60b34d3a1741586e52a328cdc40a08d4ec1bdfe7 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2018
 // Test that impl trait does not allow creating recursive types that are
 // otherwise forbidden when using `async` and `await`.
index 63f64f4455749acbec7833cd1aa24319ffdcfefd..7e63a8da552554bb8ded374641478a0bc3b54b2d 100644 (file)
@@ -1,5 +1,5 @@
 error[E0733]: recursion in an `async fn` requires boxing
-  --> $DIR/recursive-async-impl-trait-type.rs:5:40
+  --> $DIR/recursive-async-impl-trait-type.rs:8:40
    |
 LL | async fn recursive_async_function() -> () {
    |                                        ^^ recursive `async fn`
diff --git a/tests/ui/async-await/send-bound-async-closure.rs b/tests/ui/async-await/send-bound-async-closure.rs
new file mode 100644 (file)
index 0000000..4e9e730
--- /dev/null
@@ -0,0 +1,37 @@
+// edition: 2021
+// check-pass
+
+// This test verifies that we do not create a query cycle when typechecking has several inference
+// variables that point to the same generator interior type.
+
+use std::future::Future;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+type ChannelTask = Pin<Box<dyn Future<Output = ()> + Send>>;
+
+pub fn register_message_type() -> ChannelTask {
+    Box::pin(async move {
+        let f = |__cx: &mut Context<'_>| Poll::<()>::Pending;
+        PollFn { f }.await
+    })
+}
+
+struct PollFn<F> {
+    f: F,
+}
+
+impl<F> Unpin for PollFn<F> {}
+
+impl<T, F> Future for PollFn<F>
+where
+    F: FnMut(&mut Context<'_>) -> Poll<T>,
+{
+    type Output = T;
+
+    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
+        (&mut self.f)(cx)
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/unresolved_type_param.drop_tracking.stderr b/tests/ui/async-await/unresolved_type_param.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..912e2b3
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/unresolved_type_param.rs:12:5
+   |
+LL |     bar().await;
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/unresolved_type_param.rs:12:10
+   |
+LL |     bar().await;
+   |          ^^^^^^
+
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/unresolved_type_param.rs:12:5
+   |
+LL |     bar().await;
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/unresolved_type_param.rs:12:10
+   |
+LL |     bar().await;
+   |          ^^^^^^
+
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/unresolved_type_param.rs:12:5
+   |
+LL |     bar().await;
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/unresolved_type_param.rs:12:10
+   |
+LL |     bar().await;
+   |          ^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0698`.
diff --git a/tests/ui/async-await/unresolved_type_param.drop_tracking_mir.stderr b/tests/ui/async-await/unresolved_type_param.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..95c7994
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0282]: type annotations needed
+  --> $DIR/unresolved_type_param.rs:12:5
+   |
+LL |     bar().await;
+   |     ^^^ cannot infer type of the type parameter `T` declared on the function `bar`
+   |
+help: consider specifying the generic argument
+   |
+LL |     bar::<T>().await;
+   |        +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/async-await/unresolved_type_param.no_drop_tracking.stderr b/tests/ui/async-await/unresolved_type_param.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..16d618c
--- /dev/null
@@ -0,0 +1,63 @@
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/unresolved_type_param.rs:12:5
+   |
+LL |     bar().await;
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/unresolved_type_param.rs:12:10
+   |
+LL |     bar().await;
+   |          ^^^^^^
+
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/unresolved_type_param.rs:12:5
+   |
+LL |     bar().await;
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/unresolved_type_param.rs:12:10
+   |
+LL |     bar().await;
+   |          ^^^^^^
+
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/unresolved_type_param.rs:12:5
+   |
+LL |     bar().await;
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/unresolved_type_param.rs:12:10
+   |
+LL |     bar().await;
+   |          ^^^^^^
+
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/unresolved_type_param.rs:12:5
+   |
+LL |     bar().await;
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/unresolved_type_param.rs:12:10
+   |
+LL |     bar().await;
+   |          ^^^^^^
+
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/unresolved_type_param.rs:12:5
+   |
+LL |     bar().await;
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/unresolved_type_param.rs:12:10
+   |
+LL |     bar().await;
+   |          ^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0698`.
index 6d6d80614910403afb7e5d2816d21c72eca30d14..ca0a92b9434732294d297310954a4c38f3bff067 100644 (file)
@@ -1,24 +1,36 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // Provoke an unresolved type error (T).
 // Error message should pinpoint the type parameter T as needing to be bound
 // (rather than give a general error message)
 // edition:2018
-// compile-flags: -Zdrop-tracking
 
 async fn bar<T>() -> () {}
 
 async fn foo() {
     bar().await;
-    //~^ ERROR type inside `async fn` body must be known in this context
-    //~| ERROR type inside `async fn` body must be known in this context
-    //~| ERROR type inside `async fn` body must be known in this context
-    //~| NOTE cannot infer type for type parameter `T`
-    //~| NOTE cannot infer type for type parameter `T`
-    //~| NOTE cannot infer type for type parameter `T`
-    //~| NOTE the type is part of the `async fn` body because of this `await`
-    //~| NOTE the type is part of the `async fn` body because of this `await`
-    //~| NOTE the type is part of the `async fn` body because of this `await`
-    //~| NOTE in this expansion of desugaring of `await`
-    //~| NOTE in this expansion of desugaring of `await`
-    //~| NOTE in this expansion of desugaring of `await`
+    //[drop_tracking_mir]~^ ERROR type annotations needed
+    //[drop_tracking_mir]~| NOTE cannot infer type of the type parameter `T`
+    //[no_drop_tracking,drop_tracking]~^^^ ERROR type inside `async fn` body must be known in this context
+    //[no_drop_tracking,drop_tracking]~| ERROR type inside `async fn` body must be known in this context
+    //[no_drop_tracking,drop_tracking]~| ERROR type inside `async fn` body must be known in this context
+    //[no_drop_tracking,drop_tracking]~| NOTE cannot infer type for type parameter `T`
+    //[no_drop_tracking,drop_tracking]~| NOTE cannot infer type for type parameter `T`
+    //[no_drop_tracking,drop_tracking]~| NOTE cannot infer type for type parameter `T`
+    //[no_drop_tracking,drop_tracking]~| NOTE the type is part of the `async fn` body because of this `await`
+    //[no_drop_tracking,drop_tracking]~| NOTE the type is part of the `async fn` body because of this `await`
+    //[no_drop_tracking,drop_tracking]~| NOTE the type is part of the `async fn` body because of this `await`
+    //[no_drop_tracking,drop_tracking]~| NOTE in this expansion of desugaring of `await`
+    //[no_drop_tracking,drop_tracking]~| NOTE in this expansion of desugaring of `await`
+    //[no_drop_tracking,drop_tracking]~| NOTE in this expansion of desugaring of `await`
+    //[no_drop_tracking]~^^^^^^^^^^^^^^^ ERROR type inside `async fn` body must be known in this context
+    //[no_drop_tracking]~| ERROR type inside `async fn` body must be known in this context
+    //[no_drop_tracking]~| NOTE cannot infer type for type parameter `T`
+    //[no_drop_tracking]~| NOTE cannot infer type for type parameter `T`
+    //[no_drop_tracking]~| NOTE the type is part of the `async fn` body because of this `await`
+    //[no_drop_tracking]~| NOTE the type is part of the `async fn` body because of this `await`
+    //[no_drop_tracking]~| NOTE in this expansion of desugaring of `await`
+    //[no_drop_tracking]~| NOTE in this expansion of desugaring of `await`
 }
 fn main() {}
index 7236c681f341cef1080752841952136c960f3472..64a31b5fc32dc3bf6c23f9f648d35a5c46d6d304 100644 (file)
@@ -1,35 +1,35 @@
 error[E0698]: type inside `async fn` body must be known in this context
-  --> $DIR/unresolved_type_param.rs:10:5
+  --> $DIR/unresolved_type_param.rs:13:5
    |
 LL |     bar().await;
    |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
    |
 note: the type is part of the `async fn` body because of this `await`
-  --> $DIR/unresolved_type_param.rs:10:10
+  --> $DIR/unresolved_type_param.rs:13:10
    |
 LL |     bar().await;
    |          ^^^^^^
 
 error[E0698]: type inside `async fn` body must be known in this context
-  --> $DIR/unresolved_type_param.rs:10:5
+  --> $DIR/unresolved_type_param.rs:13:5
    |
 LL |     bar().await;
    |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
    |
 note: the type is part of the `async fn` body because of this `await`
-  --> $DIR/unresolved_type_param.rs:10:10
+  --> $DIR/unresolved_type_param.rs:13:10
    |
 LL |     bar().await;
    |          ^^^^^^
 
 error[E0698]: type inside `async fn` body must be known in this context
-  --> $DIR/unresolved_type_param.rs:10:5
+  --> $DIR/unresolved_type_param.rs:13:5
    |
 LL |     bar().await;
    |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
    |
 note: the type is part of the `async fn` body because of this `await`
-  --> $DIR/unresolved_type_param.rs:10:10
+  --> $DIR/unresolved_type_param.rs:13:10
    |
 LL |     bar().await;
    |          ^^^^^^
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
 
diff --git a/tests/ui/borrowck/issue-92157.rs b/tests/ui/borrowck/issue-92157.rs
new file mode 100644 (file)
index 0000000..6ee2320
--- /dev/null
@@ -0,0 +1,40 @@
+#![feature(no_core)]
+#![feature(lang_items)]
+
+#![no_core]
+
+#[cfg(target_os = "linux")]
+#[link(name = "c")]
+extern {}
+
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+    //~^ ERROR: incorrect number of parameters for the `start` lang item
+    40+2
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    drop_in_place(to_drop)
+}
+
+#[lang = "add"]
+trait Add<RHS> {
+    type Output;
+    fn add(self, other: RHS) -> Self::Output;
+}
+
+impl Add<isize> for isize {
+    type Output = isize;
+    fn add(self, other: isize) -> isize {
+        self + other
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-92157.stderr b/tests/ui/borrowck/issue-92157.stderr
new file mode 100644 (file)
index 0000000..a4010d7
--- /dev/null
@@ -0,0 +1,11 @@
+error: incorrect number of parameters for the `start` lang item
+  --> $DIR/issue-92157.rs:11:1
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `start` lang item should have four parameters, but found 3
+   = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+
+error: aborting due to previous error
+
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 1aed218aeb473c2bef1345b6e08c827f3502fcef..fbebc80d91ced614a38fe76cf3acc64cf3313e9f 100644 (file)
@@ -2,8 +2,12 @@ fn main() {
     let u = 5 as bool; //~ ERROR cannot cast as `bool`
                        //~| HELP compare with zero instead
                        //~| SUGGESTION 5 != 0
+
     let t = (1 + 2) as bool; //~ ERROR cannot cast as `bool`
                              //~| HELP compare with zero instead
                              //~| SUGGESTION (1 + 2) != 0
-    let v = "hello" as bool; //~ ERROR casting `&'static str` as `bool` is invalid
+
+    let v = "hello" as bool;
+    //~^ ERROR casting `&'static str` as `bool` is invalid
+    //~| HELP consider using the `is_empty` method on `&'static str` to determine if it contains anything
 }
index 15d94ab69d88c707016c314e0286620ff5855a94..19ac8f10fec216abdaf92214f69d3086aeb1791b 100644 (file)
@@ -5,16 +5,21 @@ LL |     let u = 5 as bool;
    |             ^^^^^^^^^ help: compare with zero instead: `5 != 0`
 
 error[E0054]: cannot cast as `bool`
-  --> $DIR/cast-as-bool.rs:5:13
+  --> $DIR/cast-as-bool.rs:6:13
    |
 LL |     let t = (1 + 2) as bool;
    |             ^^^^^^^^^^^^^^^ help: compare with zero instead: `(1 + 2) != 0`
 
 error[E0606]: casting `&'static str` as `bool` is invalid
-  --> $DIR/cast-as-bool.rs:8:13
+  --> $DIR/cast-as-bool.rs:10:13
    |
 LL |     let v = "hello" as bool;
    |             ^^^^^^^^^^^^^^^
+   |
+help: consider using the `is_empty` method on `&'static str` to determine if it contains anything
+   |
+LL |     let v = !"hello".is_empty();
+   |             +       ~~~~~~~~~~~
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/cast/issue-106883-is-empty.rs b/tests/ui/cast/issue-106883-is-empty.rs
new file mode 100644 (file)
index 0000000..27e0816
--- /dev/null
@@ -0,0 +1,27 @@
+use std::ops::Deref;
+
+struct Foo;
+
+impl Deref for Foo {
+    type Target = [u8];
+
+    fn deref(&self) -> &Self::Target {
+        &[]
+    }
+}
+
+fn main() {
+    let _ = "foo" as bool;
+    //~^ ERROR casting `&'static str` as `bool` is invalid [E0606]
+
+    let _ = String::from("foo") as bool;
+    //~^ ERROR non-primitive cast: `String` as `bool` [E0605]
+
+    let _ = Foo as bool;
+    //~^ ERROR non-primitive cast: `Foo` as `bool` [E0605]
+}
+
+fn _slice(bar: &[i32]) -> bool {
+    bar as bool
+    //~^ ERROR casting `&[i32]` as `bool` is invalid [E0606]
+}
diff --git a/tests/ui/cast/issue-106883-is-empty.stderr b/tests/ui/cast/issue-106883-is-empty.stderr
new file mode 100644 (file)
index 0000000..7115c77
--- /dev/null
@@ -0,0 +1,58 @@
+error[E0606]: casting `&'static str` as `bool` is invalid
+  --> $DIR/issue-106883-is-empty.rs:14:13
+   |
+LL |     let _ = "foo" as bool;
+   |             ^^^^^^^^^^^^^
+   |
+help: consider using the `is_empty` method on `&'static str` to determine if it contains anything
+   |
+LL |     let _ = !"foo".is_empty();
+   |             +     ~~~~~~~~~~~
+
+error[E0605]: non-primitive cast: `String` as `bool`
+  --> $DIR/issue-106883-is-empty.rs:17:13
+   |
+LL |     let _ = String::from("foo") as bool;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+   |
+note: this expression `Deref`s to `str` which implements `is_empty`
+  --> $DIR/issue-106883-is-empty.rs:17:13
+   |
+LL |     let _ = String::from("foo") as bool;
+   |             ^^^^^^^^^^^^^^^^^^^
+help: consider using the `is_empty` method on `String` to determine if it contains anything
+   |
+LL |     let _ = !String::from("foo").is_empty();
+   |             +                   ~~~~~~~~~~~
+
+error[E0605]: non-primitive cast: `Foo` as `bool`
+  --> $DIR/issue-106883-is-empty.rs:20:13
+   |
+LL |     let _ = Foo as bool;
+   |             ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+   |
+note: this expression `Deref`s to `[u8]` which implements `is_empty`
+  --> $DIR/issue-106883-is-empty.rs:20:13
+   |
+LL |     let _ = Foo as bool;
+   |             ^^^
+help: consider using the `is_empty` method on `Foo` to determine if it contains anything
+   |
+LL |     let _ = !Foo.is_empty();
+   |             +   ~~~~~~~~~~~
+
+error[E0606]: casting `&[i32]` as `bool` is invalid
+  --> $DIR/issue-106883-is-empty.rs:25:5
+   |
+LL |     bar as bool
+   |     ^^^^^^^^^^^
+   |
+help: consider using the `is_empty` method on `&[i32]` to determine if it contains anything
+   |
+LL |     !bar.is_empty()
+   |     +   ~~~~~~~~~~~
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0605, E0606.
+For more information about an error, try `rustc --explain E0605`.
index 1c69b07e3d4af0859656946d6094f3c2bb07e173..3169e4781ee2e0c18ca968683971ef3b68e0b834 100644 (file)
@@ -1,7 +1,7 @@
-// check-fail
-// known-bug
+// edition:2021
+// known-bug: unknown
 // unset-rustc-env:RUST_BACKTRACE
-// compile-flags:-Z trait-solver=chalk --edition=2021
+// compile-flags:-Z trait-solver=chalk
 // error-pattern:internal compiler error
 // failure-status:101
 // normalize-stderr-test "DefId([^)]*)" -> "..."
index d1508cb17001b4cf807bc3dcb3a0449f2854dd98..8043f1e5a05820ee01ada4cdd9d569127a8ef9e8 100644 (file)
@@ -37,7 +37,7 @@ LL | async fn foo(x: u32) -> u32 {
    = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]`
    = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited
 
-error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ...), _use_mk_alias_ty_instead: () }, Term::Ty(u32)), []), depth=0)`
+error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ...) }, Term::Ty(u32)), []), depth=0)`
   --> $DIR/async.rs:23:25
    |
 LL | async fn foo(x: u32) -> u32 {
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 59607afec8f8da20f901af644eba78a8afe679c3..1cd8949b8c4b71eddab96dc8cd9e7fd2cf802230 100644 (file)
@@ -6,6 +6,13 @@ LL |         Foo(())
    |         |
    |         arguments to this struct are incorrect
    |
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-84128.rs:13:9
+   |
+LL |         Foo(())
+   |         ^^^^--^
+   |             |
+   |             this argument influences the type of `Foo`
 note: tuple struct defined here
   --> $DIR/issue-84128.rs:5:8
    |
index 72337892734e6af3a29009053ff42133f6f92f51..b492251c01691e85ce617249bb91cf1877509608 100644 (file)
@@ -6,6 +6,13 @@ LL |     Ok(())
    |     |
    |     arguments to this enum variant are incorrect
    |
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-87461.rs:10:5
+   |
+LL |     Ok(())
+   |     ^^^--^
+   |        |
+   |        this argument influences the type of `Ok`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
 
@@ -17,6 +24,13 @@ LL |     Ok(())
    |     |
    |     arguments to this enum variant are incorrect
    |
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-87461.rs:17:5
+   |
+LL |     Ok(())
+   |     ^^^--^
+   |        |
+   |        this argument influences the type of `Ok`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
 
@@ -28,6 +42,13 @@ LL |         Ok(())
    |         |
    |         arguments to this enum variant are incorrect
    |
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-87461.rs:26:9
+   |
+LL |         Ok(())
+   |         ^^^--^
+   |            |
+   |            this argument influences the type of `Ok`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
 
index da26302c9d8a48219e8845a02c3820b764b95d4d..32a1edb0024c0da0e3bafa83f17d5f022d3432fc 100644 (file)
@@ -2,10 +2,8 @@ error[E0631]: type mismatch in closure arguments
   --> $DIR/multiple-fn-bounds.rs:10:5
    |
 LL |     foo(move |x| v);
-   |     ^^^ --------
-   |     |   |     |
-   |     |   |     help: do not borrow the argument: `char`
-   |     |   found signature defined here
+   |     ^^^ -------- found signature defined here
+   |     |
    |     expected due to this
    |
    = note: expected closure signature `fn(char) -> _`
@@ -20,6 +18,10 @@ note: required by a bound in `foo`
    |
 LL | fn foo<F: Fn(&char) -> bool + Fn(char) -> bool>(f: F) {
    |                               ^^^^^^^^^^^^^^^^ required by this bound in `foo`
+help: do not borrow the argument
+   |
+LL |     foo(move |char| v);
+   |               ~~~~
 
 error: aborting due to previous error
 
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 70665ba06f95435b138f5c608ae0d2dfed43153f..5eb8dc2a4687f53181f707efdea2267c79b558dd 100644 (file)
@@ -1,5 +1,11 @@
 // Test that encountering closures during coherence does not cause issues.
 #![feature(type_alias_impl_trait, generators)]
+#![cfg_attr(specialized, feature(specialization))]
+#![allow(incomplete_features)]
+
+// revisions: stock specialized
+// [specialized]check-pass
+
 type OpaqueGenerator = impl Sized;
 fn defining_use() -> OpaqueGenerator {
     || {
@@ -13,6 +19,6 @@ fn defining_use() -> OpaqueGenerator {
 trait Trait {}
 impl Trait for Wrapper<OpaqueGenerator> {}
 impl<T: Sync> Trait for Wrapper<T> {}
-//~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
+//[stock]~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
 
 fn main() {}
diff --git a/tests/ui/coherence/coherence-with-generator.stderr b/tests/ui/coherence/coherence-with-generator.stderr
deleted file mode 100644 (file)
index 6d3be2e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
-  --> $DIR/coherence-with-generator.rs:15:1
-   |
-LL | impl Trait for Wrapper<OpaqueGenerator> {}
-   | --------------------------------------- first implementation here
-LL | impl<T: Sync> Trait for Wrapper<T> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueGenerator>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/coherence/coherence-with-generator.stock.stderr b/tests/ui/coherence/coherence-with-generator.stock.stderr
new file mode 100644 (file)
index 0000000..478ac49
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
+  --> $DIR/coherence-with-generator.rs:21:1
+   |
+LL | impl Trait for Wrapper<OpaqueGenerator> {}
+   | --------------------------------------- first implementation here
+LL | impl<T: Sync> Trait for Wrapper<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueGenerator>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
index ca91643edf72735d4a885579c97c17ded0591dd2..423752ca25eba9320e7589369bb58e224cc887ac 100644 (file)
@@ -13,10 +13,34 @@ fn main() {
     let _: Wow<A.0>;
     //~^ ERROR expected one of
     //~| HELP expressions must be enclosed in braces to be used as const generic arguments
-
-    // FIXME(compiler-errors): This one is still unsatisfying,
-    // and probably a case I could see someone typing by accident..
+    let _: Wow<[]>;
+    //~^ ERROR expected type
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
     let _: Wow<[12]>;
-    //~^ ERROR expected type, found
-    //~| ERROR type provided when a constant was expected
+    //~^ ERROR expected type
+    //~| ERROR invalid const generic expression
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    let _: Wow<[0, 1, 3]>;
+    //~^ ERROR expected type
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    let _: Wow<[0xff; 8]>;
+    //~^ ERROR expected type
+    //~| ERROR invalid const generic expression
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    let _: Wow<[1, 2]>; // Regression test for issue #81698.
+    //~^ ERROR expected type
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    let _: Wow<&0>;
+    //~^ ERROR expected type
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    let _: Wow<("", 0)>;
+    //~^ ERROR expected type
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    let _: Wow<(1 + 2) * 3>;
+    //~^ ERROR expected type
+    //~| HELP expressions must be enclosed in braces to be used as const generic arguments
+    // FIXME(fmease): This one is pretty bad.
+    let _: Wow<!0>;
+    //~^ ERROR expected one of
+    //~| HELP you might have meant to end the type parameters here
 }
index 24668b08b8a568c611a1b88d654c6e3e49767e39..17a63a96fe4fe5e12a68594e8c3d521b980c80ea 100644 (file)
@@ -42,18 +42,118 @@ help: expressions must be enclosed in braces to be used as const generic argumen
 LL |     let _: Wow<{ A.0 }>;
    |                +     +
 
+error: expected type, found `]`
+  --> $DIR/bad-const-generic-exprs.rs:16:17
+   |
+LL |     let _: Wow<[]>;
+   |                 ^ expected type
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ [] }>;
+   |                +    +
+
 error: expected type, found `12`
   --> $DIR/bad-const-generic-exprs.rs:19:17
    |
 LL |     let _: Wow<[12]>;
    |                 ^^ expected type
 
-error[E0747]: type provided when a constant was expected
+error: invalid const generic expression
   --> $DIR/bad-const-generic-exprs.rs:19:16
    |
 LL |     let _: Wow<[12]>;
    |                ^^^^
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ [12] }>;
+   |                +      +
+
+error: expected type, found `0`
+  --> $DIR/bad-const-generic-exprs.rs:23:17
+   |
+LL |     let _: Wow<[0, 1, 3]>;
+   |                 ^ expected type
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ [0, 1, 3] }>;
+   |                +           +
+
+error: expected type, found `0xff`
+  --> $DIR/bad-const-generic-exprs.rs:26:17
+   |
+LL |     let _: Wow<[0xff; 8]>;
+   |                 ^^^^ expected type
+
+error: invalid const generic expression
+  --> $DIR/bad-const-generic-exprs.rs:26:16
+   |
+LL |     let _: Wow<[0xff; 8]>;
+   |                ^^^^^^^^^
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ [0xff; 8] }>;
+   |                +           +
+
+error: expected type, found `1`
+  --> $DIR/bad-const-generic-exprs.rs:30:17
+   |
+LL |     let _: Wow<[1, 2]>; // Regression test for issue #81698.
+   |                 ^ expected type
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ [1, 2] }>; // Regression test for issue #81698.
+   |                +        +
+
+error: expected type, found `0`
+  --> $DIR/bad-const-generic-exprs.rs:33:17
+   |
+LL |     let _: Wow<&0>;
+   |                 ^ expected type
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ &0 }>;
+   |                +    +
+
+error: expected type, found `""`
+  --> $DIR/bad-const-generic-exprs.rs:36:17
+   |
+LL |     let _: Wow<("", 0)>;
+   |                 ^^ expected type
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ ("", 0) }>;
+   |                +         +
+
+error: expected type, found `1`
+  --> $DIR/bad-const-generic-exprs.rs:39:17
+   |
+LL |     let _: Wow<(1 + 2) * 3>;
+   |                 ^ expected type
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     let _: Wow<{ (1 + 2) * 3 }>;
+   |                +             +
+
+error: expected one of `,` or `>`, found `0`
+  --> $DIR/bad-const-generic-exprs.rs:43:17
+   |
+LL |     let _: Wow<!0>;
+   |         -       ^ expected one of `,` or `>`
+   |         |
+   |         while parsing the type for `_`
+   |
+help: you might have meant to end the type parameters here
+   |
+LL |     let _: Wow<!>0>;
+   |                 +
 
-error: aborting due to 6 previous errors
+error: aborting due to 15 previous errors
 
-For more information about this error, try `rustc --explain E0747`.
index a7b78b80ca5ea4a1082437d88f9daf797a62270e..24aa405211f4cc3f4322b4f5911b56590da6e6a3 100644 (file)
@@ -10,7 +10,7 @@ error[E0770]: the type of const parameters must not depend on other generic para
 LL | pub struct SelfDependent<const N: [u8; N]>;
    |                                        ^ the type must not depend on the parameter `N`
 
-error: `[u8; _]` is forbidden as the type of a const generic parameter
+error: `[u8; N]` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-type-depends-on-const-param.rs:11:47
    |
 LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
@@ -19,7 +19,7 @@ LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
    = note: the only supported types are integers, `bool` and `char`
    = help: more complex types are supported with `#![feature(adt_const_params)]`
 
-error: `[u8; _]` is forbidden as the type of a const generic parameter
+error: `[u8; N]` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-type-depends-on-const-param.rs:15:35
    |
 LL | pub struct SelfDependent<const N: [u8; N]>;
index 9d50f9a47ff6ef46d8e40ed363677db70f20f7ab..64b2acb03629235f33cad7d2032359eeb4fa1a07 100644 (file)
 
 pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
 //~^ ERROR: the type of const parameters must not depend on other generic parameters
-//[min]~^^ ERROR `[u8; _]` is forbidden
+//[min]~^^ ERROR `[u8; N]` is forbidden
 
 pub struct SelfDependent<const N: [u8; N]>;
 //~^ ERROR: the type of const parameters must not depend on other generic parameters
-//[min]~^^ ERROR `[u8; _]` is forbidden
+//[min]~^^ ERROR `[u8; N]` is forbidden
 
 fn main() {}
index 68ce61bd4a374d3118ba39ab1672716dfa178189..d8eebeb0d2115c3673a4eb139a5c86703631a4be 100644 (file)
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `[Adt; _]: Foo` is not satisfied
+error[E0277]: the trait bound `[Adt; std::mem::size_of::<Self::Assoc>()]: Foo` is not satisfied
   --> $DIR/dont-evaluate-array-len-on-err-1.rs:15:9
    |
 LL |         <[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `[Adt; _]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `[Adt; std::mem::size_of::<Self::Assoc>()]`
 
 error: aborting due to previous error
 
index 041232e86907954a2e70142110fd1070dad440ca..1d10dfdf10c6ee1575d212655a3709dc0844a149 100644 (file)
@@ -10,7 +10,7 @@ error: overly complex generic constant
   --> $DIR/array-size-in-generic-struct-param.rs:19:15
    |
 LL |     arr: [u8; CFG.arr_size],
-   |               ^^^^^^^^^^^^ field access is not supported in generic constant
+   |               ^^^^^^^^^^^^ field access is not supported in generic constants
    |
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
diff --git a/tests/ui/const-generics/generic_const_exprs/auxiliary/anon_const_non_local.rs b/tests/ui/const-generics/generic_const_exprs/auxiliary/anon_const_non_local.rs
new file mode 100644 (file)
index 0000000..97be074
--- /dev/null
@@ -0,0 +1,8 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub struct Foo<const N: usize>;
+
+pub fn foo<const N: usize>() -> Foo<{ N + 1 }> {
+    Foo
+}
diff --git a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs
new file mode 100644 (file)
index 0000000..7332a8f
--- /dev/null
@@ -0,0 +1,11 @@
+#![feature(inline_const, generic_const_exprs)]
+//~^ WARN the feature `generic_const_exprs` is incomplete
+
+fn foo<T>() {
+    let _ = [0u8; const { std::mem::size_of::<T>() }];
+    //~^ ERROR: overly complex generic constant
+}
+
+fn main() {
+    foo::<i32>();
+}
diff --git a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr
new file mode 100644 (file)
index 0000000..f262599
--- /dev/null
@@ -0,0 +1,20 @@
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/const-block-is-poly.rs:1:26
+   |
+LL | #![feature(inline_const, generic_const_exprs)]
+   |                          ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: overly complex generic constant
+  --> $DIR/const-block-is-poly.rs:5:19
+   |
+LL |     let _ = [0u8; const { std::mem::size_of::<T>() }];
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ const blocks are not supported in generic constants
+   |
+   = help: consider moving this anonymous constant into a `const` function
+   = note: this operation may be supported in the future
+
+error: aborting due to previous error; 1 warning emitted
+
index 9bea4105d58b06099a7a07cfe46e581acea61060..65822856e1d7c100b25ab0e9ce4ab35be19159da 100644 (file)
@@ -15,7 +15,7 @@ LL |         ArrayHolder([0; Self::SIZE])
    |         arguments to this struct are incorrect
    |
    = note: expected array `[u32; X]`
-              found array `[u32; _]`
+              found array `[u32; Self::SIZE]`
 note: tuple struct defined here
   --> $DIR/issue-62504.rs:14:8
    |
index 029528c3a8172772da0aa816061918b95613641e..9baf9790e19b321601d2de1af2bd37bf8d08c790 100644 (file)
@@ -2,13 +2,13 @@ error[E0308]: mismatched types
   --> $DIR/issue-79518-default_trait_method_normalization.rs:16:32
    |
 LL |         Self::AssocInstance == [(); std::mem::size_of::<Self::Assoc>()];
-   |         -------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found array `[(); _]`
+   |         -------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found array `[(); std::mem::size_of::<Self::Assoc>()]`
    |         |
    |         expected because this is `<Self as Foo>::Assoc`
    |
    = note: expected associated type `<Self as Foo>::Assoc`
-                        found array `[(); _]`
-   = help: consider constraining the associated type `<Self as Foo>::Assoc` to `[(); _]` or calling a method that returns `<Self as Foo>::Assoc`
+                        found array `[(); std::mem::size_of::<Self::Assoc>()]`
+   = help: consider constraining the associated type `<Self as Foo>::Assoc` to `[(); std::mem::size_of::<Self::Assoc>()]` or calling a method that returns `<Self as Foo>::Assoc`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error: aborting due to previous error
index 5ebb4c3999c365478c09af2842e91a67e7650ac0..823a4f8a185bb8cc7020063d2568921bbdb4dd17 100644 (file)
@@ -2,7 +2,7 @@ error: overly complex generic constant
   --> $DIR/let-bindings.rs:6:68
    |
 LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
-   |                                                                    ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant
+   |                                                                    ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constants
    |
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
@@ -11,7 +11,7 @@ error: overly complex generic constant
   --> $DIR/let-bindings.rs:6:35
    |
 LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
-   |                                   ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant
+   |                                   ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constants
    |
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
diff --git a/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.rs b/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.rs
new file mode 100644 (file)
index 0000000..1254b44
--- /dev/null
@@ -0,0 +1,16 @@
+// aux-build:anon_const_non_local.rs
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+extern crate anon_const_non_local;
+
+fn bar<const M: usize>()
+where
+    [(); M + 1]:,
+{
+    let _: anon_const_non_local::Foo<2> = anon_const_non_local::foo::<M>();
+    //~^ ERROR: mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr b/tests/ui/const-generics/generic_const_exprs/non_local_anon_const_diagnostics.stderr
new file mode 100644 (file)
index 0000000..3926c83
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/non_local_anon_const_diagnostics.rs:12:43
+   |
+LL |     let _: anon_const_non_local::Foo<2> = anon_const_non_local::foo::<M>();
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `anon_const_non_local::::foo::{constant#0}`
+   |
+   = note: expected constant `2`
+              found constant `anon_const_non_local::::foo::{constant#0}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index df73acf53de65f27be074845c9c0684c74628d06..265a3b9d233414912aabdca5085cd03487b76f78 100644 (file)
@@ -2,7 +2,7 @@ error: overly complex generic constant
   --> $DIR/unused_expr.rs:4:34
    |
 LL | fn add<const N: usize>() -> [u8; { N + 1; 5 }] {
-   |                                  ^^^^^^^^^^^^ blocks are not supported in generic constant
+   |                                  ^^^^^^^^^^^^ blocks are not supported in generic constants
    |
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
@@ -11,7 +11,7 @@ error: overly complex generic constant
   --> $DIR/unused_expr.rs:9:34
    |
 LL | fn div<const N: usize>() -> [u8; { N / 1; 5 }] {
-   |                                  ^^^^^^^^^^^^ blocks are not supported in generic constant
+   |                                  ^^^^^^^^^^^^ blocks are not supported in generic constants
    |
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
@@ -20,7 +20,7 @@ error: overly complex generic constant
   --> $DIR/unused_expr.rs:16:38
    |
 LL | fn fn_call<const N: usize>() -> [u8; { foo(N); 5 }] {
-   |                                      ^^^^^^^^^^^^^ blocks are not supported in generic constant
+   |                                      ^^^^^^^^^^^^^ blocks are not supported in generic constants
    |
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
diff --git a/tests/ui/const-generics/issue-106419-struct-with-multiple-const-params.rs b/tests/ui/const-generics/issue-106419-struct-with-multiple-const-params.rs
new file mode 100644 (file)
index 0000000..8363e5a
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+#[derive(Clone)]
+struct Bar<const A: usize, const B: usize>
+where
+    [(); A as usize]:,
+    [(); B as usize]:,
+{}
+
+fn main() {}
index af029a6516bc625ae142e24a1a016c1583c1f99d..5a721720d78b5f31c8567f9cea625f31300449c5 100644 (file)
@@ -4,7 +4,7 @@ error[E0770]: the type of const parameters must not depend on other generic para
 LL | fn foo<const N: usize, const A: [u8; N]>() {}
    |                                      ^ the type must not depend on the parameter `N`
 
-error: `[u8; _]` is forbidden as the type of a const generic parameter
+error: `[u8; N]` is forbidden as the type of a const generic parameter
   --> $DIR/issue-62878.rs:5:33
    |
 LL | fn foo<const N: usize, const A: [u8; N]>() {}
index 578ce765b2fb82048309f1be5ef325f467ed28c2..4c08a484ef47b776e6d30a6cb58035df64d7f9ca 100644 (file)
@@ -4,7 +4,7 @@
 
 fn foo<const N: usize, const A: [u8; N]>() {}
 //~^ ERROR the type of const parameters must not
-//[min]~| ERROR `[u8; _]` is forbidden as the type of a const generic parameter
+//[min]~| ERROR `[u8; N]` is forbidden as the type of a const generic parameter
 
 fn main() {
     foo::<_, { [1] }>();
index cce85772aa4daab36009c35920a5a90c32bfbdc7..47429b7612f94095ec5ab8726964b3a76d34c6de 100644 (file)
@@ -8,7 +8,7 @@ LL | |         let x: Option<Box<Self>> = None;
 LL | |
 LL | |         0
 LL | |     }],
-   | |_____^ blocks are not supported in generic constant
+   | |_____^ blocks are not supported in generic constants
    |
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
index d3d9452d316eaac8730b36e6101a06be674e5ebe..98f9f83976aa79b63f76e9f798ea2cec18bfaeba 100644 (file)
@@ -7,7 +7,7 @@ LL | |         let x: Option<S> = None;
 LL | |
 LL | |         0
 LL | |     }],
-   | |_____^ blocks are not supported in generic constant
+   | |_____^ blocks are not supported in generic constants
    |
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
index 9604eb35d02b2abc1f68adf27a960755610f4a3d..c03d40a7bb832d80ee7bb2dbdaeeb2745f41150d 100644 (file)
@@ -7,7 +7,7 @@ LL | |         let x: Option<Box<S>> = None;
 LL | |
 LL | |         0
 LL | |     }],
-   | |_____^ blocks are not supported in generic constant
+   | |_____^ blocks are not supported in generic constants
    |
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
index 87ed2d4f8da8cc6cdd616f0552194b22c6886f97..998b16a79e63863787d7f6fd7990832f9e032958 100644 (file)
@@ -4,7 +4,7 @@ error[E0770]: the type of const parameters must not depend on other generic para
 LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
    |                                           ^^^ the type must not depend on the parameter `LEN`
 
-error: `[u8; _]` is forbidden as the type of a const generic parameter
+error: `[u8; LEN]` is forbidden as the type of a const generic parameter
   --> $DIR/issue-71169.rs:5:38
    |
 LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
index 617149a841893825a1823c6f14ad7d8e806c1000..e4ec6b073761346d080ee8f9c25589e68f1b84ac 100644 (file)
@@ -4,7 +4,7 @@
 
 fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
 //~^ ERROR the type of const parameters must not
-//[min]~^^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter
+//[min]~^^ ERROR `[u8; LEN]` is forbidden as the type of a const generic parameter
 fn main() {
     const DATA: [u8; 4] = *b"ABCD";
     foo::<4, DATA>();
index f2b58e59f731fd2df847a8ad008ded45c5f946f2..f03354fc472c088a8c3aa6ab1020bf0f03b03ee5 100644 (file)
@@ -1,4 +1,4 @@
-error: `[u32; _]` is forbidden as the type of a const generic parameter
+error: `[u32; LEN]` is forbidden as the type of a const generic parameter
   --> $DIR/issue-73491.rs:8:19
    |
 LL | fn hoge<const IN: [u32; LEN]>() {}
index f15c1f2d4552181e2c18d2396fa2993b58007094..482dbb04daae962eb4dbea96d171d0c7138a5f21 100644 (file)
@@ -6,6 +6,6 @@
 const LEN: usize = 1024;
 
 fn hoge<const IN: [u32; LEN]>() {}
-//[min]~^ ERROR `[u32; _]` is forbidden as the type of a const generic parameter
+//[min]~^ ERROR `[u32; LEN]` is forbidden as the type of a const generic parameter
 
 fn main() {}
index 82ffb2332404496ac404b15703266a2b3feae8fb..134c248347d3cd51facc116d257352bf2b5f4aa6 100644 (file)
@@ -1,4 +1,4 @@
-error: `[u8; _]` is forbidden as the type of a const generic parameter
+error: `[u8; 1 + 2]` is forbidden as the type of a const generic parameter
   --> $DIR/issue-74101.rs:6:18
    |
 LL | fn test<const N: [u8; 1 + 2]>() {}
@@ -7,7 +7,7 @@ LL | fn test<const N: [u8; 1 + 2]>() {}
    = note: the only supported types are integers, `bool` and `char`
    = help: more complex types are supported with `#![feature(adt_const_params)]`
 
-error: `[u8; _]` is forbidden as the type of a const generic parameter
+error: `[u8; 1 + 2]` is forbidden as the type of a const generic parameter
   --> $DIR/issue-74101.rs:9:21
    |
 LL | struct Foo<const N: [u8; 1 + 2]>;
index 6b606b9460fe22f95afc7d30e03488c213da00ee..4c9b2d3c634dacec0fa68bb4b48d094e430aadce 100644 (file)
@@ -4,9 +4,9 @@
 #![cfg_attr(full, allow(incomplete_features))]
 
 fn test<const N: [u8; 1 + 2]>() {}
-//[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter
+//[min]~^ ERROR `[u8; 1 + 2]` is forbidden as the type of a const generic parameter
 
 struct Foo<const N: [u8; 1 + 2]>;
-//[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter
+//[min]~^ ERROR `[u8; 1 + 2]` is forbidden as the type of a const generic parameter
 
 fn main() {}
index 7798ae7962983047f91dcb06498886a96467eebd..46af19ef395400c4908865e855af08d1466dc8d3 100644 (file)
@@ -1,4 +1,4 @@
-error: `[u8; _]` is forbidden as the type of a const generic parameter
+error: `[u8; Bar::<u32>::value()]` is forbidden as the type of a const generic parameter
   --> $DIR/issue-75047.rs:14:21
    |
 LL | struct Foo<const N: [u8; Bar::<u32>::value()]>;
index ee3dcf9ecec508fa9af1349197dba1f0f86f7ebc..7b6fb92bca96e04411ee2d41256bf33d9a92b8fd 100644 (file)
@@ -12,6 +12,6 @@ const fn value() -> usize {
 }
 
 struct Foo<const N: [u8; Bar::<u32>::value()]>;
-//[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter
+//[min]~^ ERROR `[u8; Bar::<u32>::value()]` is forbidden as the type of a const generic parameter
 
 fn main() {}
index 804c0ae5175a8a7304b19e22d588d0a4a8970f56..68b35a38b0f8ada52a5a18342d537854369fe012 100644 (file)
@@ -2,7 +2,7 @@ error: overly complex generic constant
   --> $DIR/issue-77357.rs:6:46
    |
 LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
-   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constants
    |
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
index 4908fb29692ccfd211e4ac4bf1a83ee05311fac2..50dd66da6dbb4505ef24919e204ad8ff24330980 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// known-bug
+// known-bug: unknown
 
 // This should not compile, as the compiler should not know
 // `A - 0` is satisfied `?x - 0` if `?x` is inferred to `A`.
@@ -10,7 +10,6 @@
 
 impl<'a> Ref<'a> {
     pub fn foo<const A: usize>() -> [(); A - 0] {
-        //~^ WARN function cannot
         Self::foo()
     }
 }
index fc690576875209fd5c91ecaf96252dc43dfab39f..896e1c7ea8dd663be2e440170f875f751e6bf677 100644 (file)
@@ -3,7 +3,6 @@ warning: function cannot return without recursing
    |
 LL |     pub fn foo<const A: usize>() -> [(); A - 0] {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
-LL |
 LL |         Self::foo()
    |         ----------- recursive call site
    |
index d6c48e63bb3ce70f98fbdbebddae06b2019356a7..909997340f36efc0d35704b01eba7cf647b9220a 100644 (file)
@@ -12,14 +12,14 @@ impl True for If<true> {}
 fn consume<T: 'static>(_val: T)
 where
     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
-    //~^ ERROR: can't compare
+    //~^ overly complex generic constant
 {
 }
 
 fn test<T: 'static>()
 where
     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
-    //~^ ERROR: can't compare
+    //~^ overly complex generic constant
 {
 }
 
index aba4b5c1a8d8d8794f8cae24f8bf22d3ad610f33..f13fd795d7a1020c98c8788c1a4798cbcebf8152 100644 (file)
@@ -1,29 +1,24 @@
-error[E0277]: can't compare `TypeId` with `_` in const contexts
-  --> $DIR/issue-90318.rs:14:28
+error: overly complex generic constant
+  --> $DIR/issue-90318.rs:14:8
    |
 LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
-   |                            ^^ no implementation for `TypeId == _`
+   |        ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^
+   |          |
+   |          borrowing is not supported in generic constants
    |
-   = help: the trait `~const PartialEq<_>` is not implemented for `TypeId`
-note: the trait `PartialEq<_>` is implemented for `TypeId`, but that implementation is not `const`
-  --> $DIR/issue-90318.rs:14:28
-   |
-LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
-   |                            ^^
+   = help: consider moving this anonymous constant into a `const` function
+   = note: this operation may be supported in the future
 
-error[E0277]: can't compare `TypeId` with `_` in const contexts
-  --> $DIR/issue-90318.rs:21:28
+error: overly complex generic constant
+  --> $DIR/issue-90318.rs:21:8
    |
 LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
-   |                            ^^ no implementation for `TypeId == _`
+   |        ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^
+   |          |
+   |          borrowing is not supported in generic constants
    |
-   = help: the trait `~const PartialEq<_>` is not implemented for `TypeId`
-note: the trait `PartialEq<_>` is implemented for `TypeId`, but that implementation is not `const`
-  --> $DIR/issue-90318.rs:21:28
-   |
-LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
-   |                            ^^
+   = help: consider moving this anonymous constant into a `const` function
+   = note: this operation may be supported in the future
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
index 9f73b91aabebfbbe2ee843665c253b02400fdb6b..cc629fd920fab89d85bebac8a9b52cfff6afba05 100644 (file)
@@ -8,7 +8,7 @@ LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
    |                                 in this macro invocation
 ...
 LL |       ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type
+   |                           ^ expected type
    |
    = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -22,26 +22,21 @@ LL |   Example::<gimme_a_const!(marker)>
    |             in this macro invocation
 ...
 LL |       ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type
+   |                           ^ expected type
    |
    = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected type, found `{`
   --> $DIR/macro-fail.rs:4:10
    |
-LL |     () => {{
-   |  __________^
-LL | |
-LL | |     const X: usize = 1337;
-LL | |     X
-LL | |   }}
-   | |___^ expected type
+LL |   () => {{
+   |          ^ expected type
 ...
-LL |     let _fail = Example::<external_macro!()>;
-   |                           -----------------
-   |                           |
-   |                           this macro call doesn't expand to a type
-   |                           in this macro invocation
+LL |   let _fail = Example::<external_macro!()>;
+   |                         -----------------
+   |                         |
+   |                         this macro call doesn't expand to a type
+   |                         in this macro invocation
    |
    = note: this error originates in the macro `external_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index 276ebf31ff8b88012faa61c24f8554150c0efbce..cff02b0d445c81e8d351fec56c4bc1e015d86923 100644 (file)
@@ -1,4 +1,14 @@
-error: `[u8; _]` is forbidden as the type of a const generic parameter
+error: `[u8; {
+           struct Foo<const N: usize>;
+       
+           impl<const N: usize> Foo<N> {
+               fn value() -> usize {
+                   N
+               }
+           }
+       
+           Foo::<17>::value()
+       }]` is forbidden as the type of a const generic parameter
   --> $DIR/nested-type.rs:6:21
    |
 LL |   struct Foo<const N: [u8; {
index d080c210e6bd291c7c53467d263d631f0993861d..4c1926387b926a4e843b3e6c5176af7d0b964c95 100644 (file)
@@ -2,10 +2,17 @@
 // run-rustfix
 #![warn(unused_braces)]
 
+macro_rules! make_1 {
+    () => {
+        1
+    }
+}
+
 struct A<const N: usize>;
 
 fn main() {
     let _: A<7>; // ok
     let _: A<7>; //~ WARN unnecessary braces
     let _: A<{ 3 + 5 }>; // ok
+    let _: A<{make_1!()}>; // ok
 }
index 47f0f8c1c96c91ba2d08368fc460b3401703b611..e9f15b401807915c0f85cf7893e8e14d67d60ab0 100644 (file)
@@ -2,10 +2,17 @@
 // run-rustfix
 #![warn(unused_braces)]
 
+macro_rules! make_1 {
+    () => {
+        1
+    }
+}
+
 struct A<const N: usize>;
 
 fn main() {
     let _: A<7>; // ok
     let _: A<{ 7 }>; //~ WARN unnecessary braces
     let _: A<{ 3 + 5 }>; // ok
+    let _: A<{make_1!()}>; // ok
 }
index 553a3a0f88ebae22e415562ff78016bcef43657b..2c8031c430020b8f86e38ab53137ab02c3783e30 100644 (file)
@@ -1,5 +1,5 @@
 warning: unnecessary braces around const expression
-  --> $DIR/unused_braces.rs:9:14
+  --> $DIR/unused_braces.rs:15:14
    |
 LL |     let _: A<{ 7 }>;
    |              ^^ ^^
diff --git a/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs b/tests/ui/consts/auxiliary/closure-in-foreign-crate.rs
new file mode 100644 (file)
index 0000000..edc7fa8
--- /dev/null
@@ -0,0 +1,8 @@
+#![crate_type = "lib"]
+#![feature(const_closures, const_trait_impl)]
+#![allow(incomplete_features)]
+
+pub const fn test() {
+    let cl = const || {};
+    cl();
+}
diff --git a/tests/ui/consts/closure-in-foreign-crate.rs b/tests/ui/consts/closure-in-foreign-crate.rs
new file mode 100644 (file)
index 0000000..fc8f480
--- /dev/null
@@ -0,0 +1,8 @@
+// aux-build:closure-in-foreign-crate.rs
+// build-pass
+
+extern crate closure_in_foreign_crate;
+
+const _: () = closure_in_foreign_crate::test();
+
+fn main() {}
index 8b58cb279f376a77ccb005913248ef46027a3144..f30bfaf3f958ce5349428b3185c6a175a28222ea 100644 (file)
@@ -1,8 +1,11 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/infinite_loop.rs:6:15
+  --> $DIR/infinite_loop.rs:6:9
    |
-LL |         while n != 0 {
-   |               ^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+LL | /         while n != 0 {
+LL | |
+LL | |             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
+LL | |         }
+   | |_________^ exceeded interpreter step limit (see `#[const_eval_limit]`)
 
 error: aborting due to previous error
 
index ce65407bbab0b5d928795c8b4fdc82297aac8625..307c1a66834105e316e559ebd2607a5cc75c6f54 100644 (file)
@@ -2,8 +2,8 @@ fn main() {
     let _ = [(); {
         let mut x = &0;
         let mut n = 0;
-        while n < 5 {
-            n = (n + 1) % 5; //~ ERROR evaluation of constant value failed
+        while n < 5 { //~ ERROR evaluation of constant value failed [E0080]
+            n = (n + 1) % 5;
             x = &0; // Materialize a new AllocId
         }
         0
index 8536ff02c6dae89b96403ba90c8fd15b61f58a3b..3aa6bd277ddcbdd3f201f281b512d9604b688cc2 100644 (file)
@@ -1,8 +1,11 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-52475.rs:6:17
+  --> $DIR/issue-52475.rs:5:9
    |
-LL |             n = (n + 1) % 5;
-   |                 ^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+LL | /         while n < 5 {
+LL | |             n = (n + 1) % 5;
+LL | |             x = &0; // Materialize a new AllocId
+LL | |         }
+   | |_________^ exceeded interpreter step limit (see `#[const_eval_limit]`)
 
 error: aborting due to previous error
 
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.rs
new file mode 100644 (file)
index 0000000..c595962
--- /dev/null
@@ -0,0 +1,36 @@
+// check-fail
+// compile-flags: -Z tiny-const-eval-limit
+
+const fn foo() {}
+
+const fn call_foo() -> u32 {
+    foo();
+    foo();
+    foo();
+    foo();
+    foo();
+
+    foo();
+    foo();
+    foo();
+    foo();
+    foo();
+
+    foo();
+    foo();
+    foo();
+    foo();
+    foo();
+
+    foo();
+    foo();
+    foo();
+    foo(); //~ ERROR evaluation of constant value failed [E0080]
+    0
+}
+
+const X: u32 = call_foo();
+
+fn main() {
+    println!("{X}");
+}
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.stderr
new file mode 100644 (file)
index 0000000..ed70975
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ctfe-fn-call.rs:28:5
+   |
+LL |     foo();
+   |     ^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+   |
+note: inside `call_foo`
+  --> $DIR/ctfe-fn-call.rs:28:5
+   |
+LL |     foo();
+   |     ^^^^^
+note: inside `X`
+  --> $DIR/ctfe-fn-call.rs:32:16
+   |
+LL | const X: u32 = call_foo();
+   |                ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.rs
new file mode 100644 (file)
index 0000000..c10b8d8
--- /dev/null
@@ -0,0 +1,19 @@
+// check-fail
+// compile-flags: -Z tiny-const-eval-limit
+
+const fn labelled_loop(n: u32) -> u32 {
+    let mut i = 0;
+    'mylabel: loop { //~ ERROR evaluation of constant value failed [E0080]
+        if i > n {
+            break 'mylabel
+        }
+        i += 1;
+    }
+    0
+}
+
+const X: u32 = labelled_loop(19);
+
+fn main() {
+    println!("{X}");
+}
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.stderr
new file mode 100644 (file)
index 0000000..d9404ed
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ctfe-labelled-loop.rs:6:5
+   |
+LL | /     'mylabel: loop {
+LL | |         if i > n {
+LL | |             break 'mylabel
+LL | |         }
+LL | |         i += 1;
+LL | |     }
+   | |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+   |
+note: inside `labelled_loop`
+  --> $DIR/ctfe-labelled-loop.rs:6:5
+   |
+LL | /     'mylabel: loop {
+LL | |         if i > n {
+LL | |             break 'mylabel
+LL | |         }
+LL | |         i += 1;
+LL | |     }
+   | |_____^
+note: inside `X`
+  --> $DIR/ctfe-labelled-loop.rs:15:16
+   |
+LL | const X: u32 = labelled_loop(19);
+   |                ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.rs
new file mode 100644 (file)
index 0000000..80ff835
--- /dev/null
@@ -0,0 +1,16 @@
+// check-fail
+// compile-flags: -Z tiny-const-eval-limit
+
+const fn recurse(n: u32) -> u32 {
+    if n == 0 {
+        n
+    } else {
+        recurse(n - 1) //~ ERROR evaluation of constant value failed [E0080]
+    }
+}
+
+const X: u32 = recurse(19);
+
+fn main() {
+    println!("{X}");
+}
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.stderr
new file mode 100644 (file)
index 0000000..ed9a311
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ctfe-recursion.rs:8:9
+   |
+LL |         recurse(n - 1)
+   |         ^^^^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+   |
+note: inside `recurse`
+  --> $DIR/ctfe-recursion.rs:8:9
+   |
+LL |         recurse(n - 1)
+   |         ^^^^^^^^^^^^^^
+note: [... 18 additional calls inside `recurse` ...]
+  --> $DIR/ctfe-recursion.rs:8:9
+   |
+LL |         recurse(n - 1)
+   |         ^^^^^^^^^^^^^^
+note: inside `X`
+  --> $DIR/ctfe-recursion.rs:12:16
+   |
+LL | const X: u32 = recurse(19);
+   |                ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs
new file mode 100644 (file)
index 0000000..ca0eec9
--- /dev/null
@@ -0,0 +1,15 @@
+// check-fail
+// compile-flags: -Z tiny-const-eval-limit
+const fn simple_loop(n: u32) -> u32 {
+    let mut index = 0;
+    while index < n { //~ ERROR evaluation of constant value failed [E0080]
+        index = index + 1;
+    }
+    0
+}
+
+const X: u32 = simple_loop(19);
+
+fn main() {
+    println!("{X}");
+}
diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.stderr
new file mode 100644 (file)
index 0000000..83ff275
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ctfe-simple-loop.rs:5:5
+   |
+LL | /     while index < n {
+LL | |         index = index + 1;
+LL | |     }
+   | |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+   |
+note: inside `simple_loop`
+  --> $DIR/ctfe-simple-loop.rs:5:5
+   |
+LL | /     while index < n {
+LL | |         index = index + 1;
+LL | |     }
+   | |_____^
+note: inside `X`
+  --> $DIR/ctfe-simple-loop.rs:11:16
+   |
+LL | const X: u32 = simple_loop(19);
+   |                ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/stable-metric/dominators-edge-case.rs b/tests/ui/consts/const-eval/stable-metric/dominators-edge-case.rs
new file mode 100644 (file)
index 0000000..0b0f361
--- /dev/null
@@ -0,0 +1,19 @@
+// check-pass
+//
+// Exercising an edge case which was found during Stage 2 compilation.
+// Compilation would fail for this code when running the `CtfeLimit`
+// MirPass (specifically when looking up the dominators).
+#![crate_type="lib"]
+
+const DUMMY: Expr = Expr::Path(ExprPath {
+    attrs: Vec::new(),
+    path: Vec::new(),
+});
+
+pub enum Expr {
+    Path(ExprPath),
+}
+pub struct ExprPath {
+    pub attrs: Vec<()>,
+    pub path: Vec<()>,
+}
index 1caf1617e213cb198ad9cbf82e80804013bbd664..08fcd1deab1d337549d3acac3b9050f95792a193 100644 (file)
@@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
    |
 LL |     A = { if let 0 = 0 { todo!() } 0 },
    |           ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL |     A = { let _0 = 0; 0 },
+   |               +
 
 error: aborting due to previous error
 
index f038ba1c8ed859314c4aa4140e4018cce0bba1c7..5d86ca4bfd17b632efd346068e0603a8afe5ae73 100644 (file)
@@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
    |
 LL |     let x: [i32; { if let 0 = 0 { todo!() } 0 }] = [];
    |                    ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL |     let x: [i32; { let _0 = 0; 0 }] = [];
+   |                        +
 
 error: aborting due to previous error
 
index b1921f8a41e48db0560471f059b83b6114ab9ec5..c8f66bb0fc027f2d0a59322a3d75753c56633cc2 100644 (file)
@@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
    |
 LL | const X: i32 = { if let 0 = 0 { todo!() } 0 };
    |                  ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL | const X: i32 = { let _0 = 0; 0 };
+   |                      +
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/const-match-check.rs:8:23
@@ -25,6 +29,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
    |
 LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 };
    |                   ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL | static Y: i32 = { let _0 = 0; 0 };
+   |                       +
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/const-match-check.rs:13:26
@@ -39,6 +47,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
    |
 LL |     const X: i32 = { if let 0 = 0 { todo!() } 0 };
    |                      ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL |     const X: i32 = { let _0 = 0; 0 };
+   |                          +
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/const-match-check.rs:19:26
@@ -53,6 +65,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
    |
 LL |     const X: i32 = { if let 0 = 0 { todo!() } 0 };
    |                      ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL |     const X: i32 = { let _0 = 0; 0 };
+   |                          +
 
 error: aborting due to 4 previous errors
 
index 46f02ce8a45337fc5a44f8fb52056992ea1958e3..17088d9995f2d1c65368333ca1f237324c2c73c7 100644 (file)
@@ -15,8 +15,8 @@ note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`..
 LL |     bytes: [u8; std::mem::size_of::<Foo>()]
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires computing layout of `Foo`...
-   = note: ...which requires computing layout of `[u8; _]`...
-   = note: ...which requires normalizing `[u8; _]`...
+   = note: ...which requires computing layout of `[u8; std::mem::size_of::<Foo>()]`...
+   = note: ...which requires normalizing `[u8; std::mem::size_of::<Foo>()]`...
    = note: ...which again requires evaluating type-level constant, completing the cycle
 note: cycle used when checking that `Foo` is well-formed
   --> $DIR/const-size_of-cycle.rs:3:1
diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs
new file mode 100644 (file)
index 0000000..f10d1c2
--- /dev/null
@@ -0,0 +1,12 @@
+// run-pass
+#![feature(const_type_id)]
+#![feature(const_trait_impl)]
+
+use std::any::TypeId;
+
+const fn main() {
+    assert!(TypeId::of::<u8>() == TypeId::of::<u8>());
+    assert!(TypeId::of::<()>() != TypeId::of::<u8>());
+    const _A: bool = TypeId::of::<u8>() < TypeId::of::<u16>();
+    // can't assert `_A` because it is not deterministic
+}
index 850aebdfb2a6df7051bd24946f4e1492f0c4a54d..a8e8ae9bb088a07737324dd98aeaf9a3ad2762df 100644 (file)
@@ -1,8 +1,11 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_eval_limit_reached.rs:6:11
+  --> $DIR/const_eval_limit_reached.rs:6:5
    |
-LL |     while x != 1000 {
-   |           ^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+LL | /     while x != 1000 {
+LL | |
+LL | |         x += 1;
+LL | |     }
+   | |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`)
 
 error: aborting due to previous error
 
index 57f94f8c6ab52d04dbcad0223d5a98a1b40865d9..ec64b956dfe2b8f99f33de8ea7daa6a80c216d41 100644 (file)
@@ -15,8 +15,8 @@ note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`..
 LL |     bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires computing layout of `Foo`...
-   = note: ...which requires computing layout of `[u8; _]`...
-   = note: ...which requires normalizing `[u8; _]`...
+   = note: ...which requires computing layout of `[u8; unsafe { intrinsics::size_of::<Foo>() }]`...
+   = note: ...which requires normalizing `[u8; unsafe { intrinsics::size_of::<Foo>() }]`...
    = note: ...which again requires evaluating type-level constant, completing the cycle
 note: cycle used when checking that `Foo` is well-formed
   --> $DIR/issue-44415.rs:5:1
index 7706a97f23b4834bd0c2166e8354c0659ca34f4b..addcc1eaab60bb514d472f03d09109ea267aba38 100644 (file)
@@ -7,6 +7,7 @@
 
 #![feature(const_type_id)]
 #![feature(const_type_name)]
+#![feature(const_trait_impl)]
 
 use std::any::{self, TypeId};
 
@@ -17,7 +18,7 @@ impl<T: 'static> GetTypeId<T> {
 }
 
 const fn check_type_id<T: 'static>() -> bool {
-    matches!(GetTypeId::<T>::VALUE, GetTypeId::<usize>::VALUE)
+    GetTypeId::<T>::VALUE == GetTypeId::<usize>::VALUE
 }
 
 pub struct GetTypeNameLen<T>(T);
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 af494e37349146f91cb3a196a0dc5a1df5d849b0..8b3f4b714e1bd33662001b965d3d24a2429cbc6e 100644 (file)
@@ -7,7 +7,7 @@ pub fn crash() -> bool {
         [5; Self::HOST_SIZE] == [6; 0]
         //~^ ERROR constant expression depends on a generic parameter
         //~| ERROR constant expression depends on a generic parameter
-        //~| ERROR can't compare `[{integer}; _]` with `[{integer}; 0]`
+        //~| ERROR can't compare `[{integer}; Self::HOST_SIZE]` with `[{integer}; 0]`
     }
 }
 
index 8de61fcfb7330cc36fc1039076f90bdb18278435..5af82a3e34bf5f3959debe01554ac8da4d833a35 100644 (file)
@@ -14,13 +14,13 @@ LL |         [5; Self::HOST_SIZE] == [6; 0]
    |
    = note: this may fail depending on what value the parameter takes
 
-error[E0277]: can't compare `[{integer}; _]` with `[{integer}; 0]`
+error[E0277]: can't compare `[{integer}; Self::HOST_SIZE]` with `[{integer}; 0]`
   --> $DIR/too_generic_eval_ice.rs:7:30
    |
 LL |         [5; Self::HOST_SIZE] == [6; 0]
-   |                              ^^ no implementation for `[{integer}; _] == [{integer}; 0]`
+   |                              ^^ no implementation for `[{integer}; Self::HOST_SIZE] == [{integer}; 0]`
    |
-   = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; _]`
+   = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; Self::HOST_SIZE]`
    = help: the following other types implement trait `PartialEq<Rhs>`:
              <&[B] as PartialEq<[A; N]>>
              <&[T] as PartialEq<Vec<U, A>>>
index 851dca84c3dc01dcfef6885905eca960f54b85e0..d5991bcf5693df726787ee5cb4f2ed4005fd4cf2 100644 (file)
@@ -1,4 +1,4 @@
-error: values of the type `[u8; SIZE]` are too big for the current architecture
+error: values of the type `[u8; usize::MAX]` are too big for the current architecture
 
 error: aborting due to previous error
 
index 851dca84c3dc01dcfef6885905eca960f54b85e0..d5991bcf5693df726787ee5cb4f2ed4005fd4cf2 100644 (file)
@@ -1,4 +1,4 @@
-error: values of the type `[u8; SIZE]` are too big for the current architecture
+error: values of the type `[u8; usize::MAX]` are too big for the current architecture
 
 error: aborting due to previous error
 
diff --git a/tests/ui/dep-graph/dep-graph-dump.rs b/tests/ui/dep-graph/dep-graph-dump.rs
new file mode 100644 (file)
index 0000000..cbc4def
--- /dev/null
@@ -0,0 +1,6 @@
+// Test dump-dep-graph requires query-dep-graph enabled
+
+// incremental
+// compile-flags: -Z dump-dep-graph
+
+fn main() {}
diff --git a/tests/ui/dep-graph/dep-graph-dump.stderr b/tests/ui/dep-graph/dep-graph-dump.stderr
new file mode 100644 (file)
index 0000000..ea44b8b
--- /dev/null
@@ -0,0 +1,2 @@
+error: can't dump dependency graph without `-Z query-dep-graph`
+
index bf0bb3fbdf8f7f26a6a920f8f5be9cfe30b59a06..af03f0e5e5f430ca1bbefa70b91c941ee1038600 100644 (file)
@@ -6,12 +6,15 @@ LL | struct Value(u32);
    | |
    | doesn't satisfy `Value: Eq`
    | doesn't satisfy `Value: Hash`
+   | doesn't satisfy `Value: PartialEq`
 ...
 LL |     hs.insert(Value(0));
    |        ^^^^^^
    |
    = note: the following trait bounds were not satisfied:
            `Value: Eq`
+           `Value: PartialEq`
+           which is required by `Value: Eq`
            `Value: Hash`
 help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]`
    |
@@ -22,7 +25,10 @@ error[E0599]: the method `use_eq` exists for struct `Object<NoDerives>`, but its
   --> $DIR/issue-91550.rs:26:9
    |
 LL | pub struct NoDerives;
-   | -------------------- doesn't satisfy `NoDerives: Eq`
+   | --------------------
+   | |
+   | doesn't satisfy `NoDerives: Eq`
+   | doesn't satisfy `NoDerives: PartialEq`
 LL |
 LL | struct Object<T>(T);
    | ---------------- method `use_eq` not found for this struct
@@ -37,6 +43,9 @@ LL | impl<T: Eq> Object<T> {
    |         ^^  ---------
    |         |
    |         unsatisfied trait bound introduced here
+   = note: the following trait bounds were not satisfied:
+           `NoDerives: PartialEq`
+           which is required by `NoDerives: Eq`
 help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]`
    |
 LL | #[derive(Eq, PartialEq)]
@@ -46,7 +55,12 @@ error[E0599]: the method `use_ord` exists for struct `Object<NoDerives>`, but it
   --> $DIR/issue-91550.rs:27:9
    |
 LL | pub struct NoDerives;
-   | -------------------- doesn't satisfy `NoDerives: Ord`
+   | --------------------
+   | |
+   | doesn't satisfy `NoDerives: Eq`
+   | doesn't satisfy `NoDerives: Ord`
+   | doesn't satisfy `NoDerives: PartialEq`
+   | doesn't satisfy `NoDerives: PartialOrd`
 LL |
 LL | struct Object<T>(T);
    | ---------------- method `use_ord` not found for this struct
@@ -61,6 +75,13 @@ LL | impl<T: Ord> Object<T> {
    |         ^^^  ---------
    |         |
    |         unsatisfied trait bound introduced here
+   = note: the following trait bounds were not satisfied:
+           `NoDerives: PartialOrd`
+           which is required by `NoDerives: Ord`
+           `NoDerives: PartialEq`
+           which is required by `NoDerives: Ord`
+           `NoDerives: Eq`
+           which is required by `NoDerives: Ord`
 help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
    |
 LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
@@ -72,7 +93,9 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object<NoD
 LL | pub struct NoDerives;
    | --------------------
    | |
+   | doesn't satisfy `NoDerives: Eq`
    | doesn't satisfy `NoDerives: Ord`
+   | doesn't satisfy `NoDerives: PartialEq`
    | doesn't satisfy `NoDerives: PartialOrd`
 LL |
 LL | struct Object<T>(T);
@@ -91,6 +114,13 @@ LL | impl<T: Ord + PartialOrd> Object<T> {
    |         |     |
    |         |     unsatisfied trait bound introduced here
    |         unsatisfied trait bound introduced here
+   = note: the following trait bounds were not satisfied:
+           `NoDerives: PartialEq`
+           which is required by `NoDerives: Ord`
+           `NoDerives: Eq`
+           which is required by `NoDerives: Ord`
+           `NoDerives: PartialEq`
+           which is required by `NoDerives: PartialOrd`
 help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
    |
 LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
index a63cbd4ca7edea3d2227db9b81300925274fe3c4..2a93a05c627698a2e1eb03e57133fed99215a508 100644 (file)
@@ -731,11 +731,12 @@ impl ::core::marker::Copy for Fieldless { }
 #[automatically_derived]
 impl ::core::fmt::Debug for Fieldless {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-        match self {
-            Fieldless::A => ::core::fmt::Formatter::write_str(f, "A"),
-            Fieldless::B => ::core::fmt::Formatter::write_str(f, "B"),
-            Fieldless::C => ::core::fmt::Formatter::write_str(f, "C"),
-        }
+        ::core::fmt::Formatter::write_str(f,
+            match self {
+                Fieldless::A => "A",
+                Fieldless::B => "B",
+                Fieldless::C => "C",
+            })
     }
 }
 #[automatically_derived]
@@ -888,23 +889,20 @@ impl ::core::cmp::PartialOrd for Mixed {
         -> ::core::option::Option<::core::cmp::Ordering> {
         let __self_tag = ::core::intrinsics::discriminant_value(self);
         let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-        match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) {
-            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
-                match (self, other) {
-                    (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
-                        ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
-                    (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S {
-                        d1: __arg1_0, d2: __arg1_1 }) =>
-                        match ::core::cmp::PartialOrd::partial_cmp(__self_0,
-                                __arg1_0) {
-                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
-                                => ::core::cmp::PartialOrd::partial_cmp(__self_1, __arg1_1),
-                            cmp => cmp,
-                        },
-                    _ =>
-                        ::core::option::Option::Some(::core::cmp::Ordering::Equal),
+        match (self, other) {
+            (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
+                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+            (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S {
+                d1: __arg1_0, d2: __arg1_1 }) =>
+                match ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0)
+                    {
+                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
+                        => ::core::cmp::PartialOrd::partial_cmp(__self_1, __arg1_1),
+                    cmp => cmp,
                 },
-            cmp => cmp,
+            _ =>
+                ::core::cmp::PartialOrd::partial_cmp(&__self_tag,
+                    &__arg1_tag),
         }
     }
 }
@@ -1018,18 +1016,16 @@ impl ::core::cmp::PartialOrd for Fielded {
         -> ::core::option::Option<::core::cmp::Ordering> {
         let __self_tag = ::core::intrinsics::discriminant_value(self);
         let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-        match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) {
-            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
-                match (self, other) {
-                    (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
-                        ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
-                    (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
-                        ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
-                    (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
-                        ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
-                    _ => unsafe { ::core::intrinsics::unreachable() }
-                },
-            cmp => cmp,
+        match (self, other) {
+            (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
+                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+            (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
+                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+            (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
+                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+            _ =>
+                ::core::cmp::PartialOrd::partial_cmp(&__self_tag,
+                    &__arg1_tag),
         }
     }
 }
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 700f6616af40ff02586e2c66752b0d326aa32ef1..e0b3b8685d6eb02ea62254083bbe848c6d168596 100644 (file)
@@ -4,7 +4,7 @@ error: cannot find macro `macro_two` in this scope
 LL |     macro_two!();
    |     ^^^^^^^^^
    |
-   = note: consider importing this macro:
+   = help: consider importing this macro:
            two_macros::macro_two
 
 error: aborting due to previous error
diff --git a/tests/ui/error-codes/E0208.rs b/tests/ui/error-codes/E0208.rs
new file mode 100644 (file)
index 0000000..74c138a
--- /dev/null
@@ -0,0 +1,8 @@
+#![feature(rustc_attrs)]
+
+#[rustc_variance]
+struct Foo<'a, T> { //~ ERROR [+, o]
+    t: &'a mut T,
+}
+
+fn main() {}
diff --git a/tests/ui/error-codes/E0208.stderr b/tests/ui/error-codes/E0208.stderr
new file mode 100644 (file)
index 0000000..2c7072a
--- /dev/null
@@ -0,0 +1,8 @@
+error: [+, o]
+  --> $DIR/E0208.rs:4:1
+   |
+LL | struct Foo<'a, T> {
+   | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
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 |
index cb0d8cfc31e235d49d095af3d68deca3c3c2b614..6f6c6513846cf228c0deeaad8c651af0faee273c 100644 (file)
@@ -1,3 +1,4 @@
 fn main() {
-    &0u8 as u8; //~ ERROR E0606
+    let x = &(&0u8 as u8); //~ ERROR E0606
+    x as u8; //~ casting `&u8` as `u8` is invalid [E0606]
 }
index fce24886eb0df82529ddf36c3c9c368f41cc9aff..2492eb299cc55b39de13f96225feee7ebfb76f79 100644 (file)
@@ -1,12 +1,26 @@
 error[E0606]: casting `&u8` as `u8` is invalid
-  --> $DIR/E0606.rs:2:5
+  --> $DIR/E0606.rs:2:14
    |
-LL |     &0u8 as u8;
-   |     ----^^^^^^
-   |     |
-   |     cannot cast `&u8` as `u8`
-   |     help: dereference the expression: `*&0u8`
+LL |     let x = &(&0u8 as u8);
+   |              ^^^^^^^^^^^^
+   |
+help: remove the unneeded borrow
+   |
+LL -     let x = &(&0u8 as u8);
+LL +     let x = &(0u8 as u8);
+   |
+
+error[E0606]: casting `&u8` as `u8` is invalid
+  --> $DIR/E0606.rs:3:5
+   |
+LL |     x as u8;
+   |     ^^^^^^^
+   |
+help: dereference the expression
+   |
+LL |     *x as u8;
+   |     +
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0606`.
diff --git a/tests/ui/error-codes/E0789.rs b/tests/ui/error-codes/E0789.rs
new file mode 100644 (file)
index 0000000..c0cbbcc
--- /dev/null
@@ -0,0 +1,12 @@
+// compile-flags: --crate-type lib
+
+#![feature(rustc_attrs)]
+#![feature(staged_api)]
+#![unstable(feature = "foo_module", reason = "...", issue = "123")]
+
+#[rustc_allowed_through_unstable_modules]
+// #[stable(feature = "foo", since = "1.0")]
+struct Foo;
+//~^ ERROR `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
+//~^^ ERROR `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
+// FIXME: we shouldn't have two errors here, only occurs when using `-Zdeduplicate-diagnostics=no`
diff --git a/tests/ui/error-codes/E0789.stderr b/tests/ui/error-codes/E0789.stderr
new file mode 100644 (file)
index 0000000..faab92b
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0789]: `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
+  --> $DIR/E0789.rs:9:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^^
+
+error[E0789]: `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
+  --> $DIR/E0789.rs:9:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0789`.
index fe9956b70bdd75f3e9cb374adbb589cde91d2e50..e8ee1d96942f782562f80881dabc2b6f78846af4 100644 (file)
@@ -69,10 +69,12 @@ error[E0606]: casting `&u8` as `u32` is invalid
   --> $DIR/error-festival.rs:37:18
    |
 LL |     let y: u32 = x as u32;
-   |                  -^^^^^^^
-   |                  |
-   |                  cannot cast `&u8` as `u32`
-   |                  help: dereference the expression: `*x`
+   |                  ^^^^^^^^
+   |
+help: dereference the expression
+   |
+LL |     let y: u32 = *x as u32;
+   |                  +
 
 error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
   --> $DIR/error-festival.rs:41:5
diff --git a/tests/ui/errors/auxiliary/remapped_dep.rs b/tests/ui/errors/auxiliary/remapped_dep.rs
new file mode 100644 (file)
index 0000000..f9bb7bf
--- /dev/null
@@ -0,0 +1,4 @@
+// compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux
+// no-remap-src-base: Manually remap, so the remapped path remains in .stderr file.
+
+pub struct SomeStruct {} // This line should be show as part of the error.
diff --git a/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr
new file mode 100644 (file)
index 0000000..51e3b77
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0423]: expected value, found struct `remapped_dep::SomeStruct`
+  --> $DIR/remap-path-prefix-reverse.rs:16:13
+   |
+LL |     let _ = remapped_dep::SomeStruct; // ~ERROR E0423
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}`
+   |
+  ::: remapped-aux/remapped_dep.rs:4:1
+   |
+LL | pub struct SomeStruct {} // This line should be show as part of the error.
+   | --------------------- `remapped_dep::SomeStruct` defined here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0423`.
diff --git a/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr
new file mode 100644 (file)
index 0000000..51e3b77
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0423]: expected value, found struct `remapped_dep::SomeStruct`
+  --> $DIR/remap-path-prefix-reverse.rs:16:13
+   |
+LL |     let _ = remapped_dep::SomeStruct; // ~ERROR E0423
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}`
+   |
+  ::: remapped-aux/remapped_dep.rs:4:1
+   |
+LL | pub struct SomeStruct {} // This line should be show as part of the error.
+   | --------------------- `remapped_dep::SomeStruct` defined here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0423`.
diff --git a/tests/ui/errors/remap-path-prefix-reverse.rs b/tests/ui/errors/remap-path-prefix-reverse.rs
new file mode 100644 (file)
index 0000000..71c8006
--- /dev/null
@@ -0,0 +1,17 @@
+// aux-build:remapped_dep.rs
+// compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux
+
+// revisions: local-self remapped-self
+// [local-self] no-remap-src-base: The hack should work regardless of remapping.
+// [remapped-self] remap-src-base
+
+// Verify that the expected source code is shown.
+// error-pattern: pub struct SomeStruct {} // This line should be show
+
+extern crate remapped_dep;
+
+fn main() {
+    // The actual error is irrelevant. The important part it that is should show
+    // a snippet of the dependency's source.
+    let _ = remapped_dep::SomeStruct; // ~ERROR E0423
+}
diff --git a/tests/ui/errors/remap-path-prefix.rs b/tests/ui/errors/remap-path-prefix.rs
new file mode 100644 (file)
index 0000000..393b8e2
--- /dev/null
@@ -0,0 +1,17 @@
+// compile-flags: --remap-path-prefix={{src-base}}=remapped
+// no-remap-src-base: Manually remap, so the remapped path remains in .stderr file.
+
+// The remapped paths are not normalized by compiletest.
+// normalize-stderr-test: "\\(errors)" -> "/$1"
+
+// The remapped paths aren't recognized by compiletest, so we
+// cannot use line-specific patterns.
+// error-pattern: E0425
+
+fn main() {
+    // We cannot actually put an ERROR marker here because
+    // the file name in the error message is not what the
+    // test framework expects (since the filename gets remapped).
+    // We still test the expected error in the stderr file.
+    ferris
+}
diff --git a/tests/ui/errors/remap-path-prefix.stderr b/tests/ui/errors/remap-path-prefix.stderr
new file mode 100644 (file)
index 0000000..62dbd4b
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `ferris` in this scope
+  --> remapped/errors/remap-path-prefix.rs:16:5
+   |
+LL |     ferris
+   |     ^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
index 63797d4a71bce7f04b1fb44f4609db974f36fadd..92e8a44b55fe570fd2fdacf0fd9f4f1aedc8c01f 100644 (file)
@@ -30,7 +30,7 @@ LL |     use env;
 help: consider importing this module instead
    |
 LL |     use std::env;
-   |         ~~~~~~~~~
+   |         ~~~~~~~~
 
 error: cannot determine resolution for the macro `env`
   --> $DIR/issue-55897.rs:6:22
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`.
diff --git a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs
new file mode 100644 (file)
index 0000000..0467dea
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+
+#![deny(multiple_supertrait_upcastable)]
+//~^ WARNING unknown lint: `multiple_supertrait_upcastable`
+//~| WARNING unknown lint: `multiple_supertrait_upcastable`
+//~| WARNING unknown lint: `multiple_supertrait_upcastable`
+#![warn(multiple_supertrait_upcastable)]
+//~^ WARNING unknown lint: `multiple_supertrait_upcastable`
+//~| WARNING unknown lint: `multiple_supertrait_upcastable`
+//~| WARNING unknown lint: `multiple_supertrait_upcastable`
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr
new file mode 100644 (file)
index 0000000..1f725f3
--- /dev/null
@@ -0,0 +1,57 @@
+warning: unknown lint: `multiple_supertrait_upcastable`
+  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
+   |
+LL | #![deny(multiple_supertrait_upcastable)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `multiple_supertrait_upcastable` lint is unstable
+   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+   = note: `#[warn(unknown_lints)]` on by default
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
+   |
+LL | #![warn(multiple_supertrait_upcastable)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `multiple_supertrait_upcastable` lint is unstable
+   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
+   |
+LL | #![deny(multiple_supertrait_upcastable)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `multiple_supertrait_upcastable` lint is unstable
+   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
+   |
+LL | #![warn(multiple_supertrait_upcastable)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `multiple_supertrait_upcastable` lint is unstable
+   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
+   |
+LL | #![deny(multiple_supertrait_upcastable)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `multiple_supertrait_upcastable` lint is unstable
+   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
+   |
+LL | #![warn(multiple_supertrait_upcastable)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `multiple_supertrait_upcastable` lint is unstable
+   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: 6 warnings emitted
+
index 539c8fb27b3b0a5b5909b4e791da7d7f3d68bc03..1b7ef93f41d575abb3e3c0c05b1d615207a357b4 100644 (file)
@@ -28,6 +28,7 @@ pub fn err_with_input_span(input: TokenStream) -> TokenStream {
     TokenStream::from(TokenTree::Literal(lit))
 }
 
+
 #[proc_macro]
 pub fn respan_to_invalid_format_literal(input: TokenStream) -> TokenStream {
     let mut s = Literal::string("{");
@@ -38,3 +39,14 @@ pub fn respan_to_invalid_format_literal(input: TokenStream) -> TokenStream {
         TokenTree::from(Group::new(Delimiter::Parenthesis, TokenTree::from(s).into())),
     ])
 }
+
+#[proc_macro]
+pub fn capture_a_with_prepended_space_preserve_span(input: TokenStream) -> TokenStream {
+    let mut s = Literal::string(" {a}");
+    s.set_span(input.into_iter().next().unwrap().span());
+    TokenStream::from_iter([
+        TokenTree::from(Ident::new("format", Span::call_site())),
+        TokenTree::from(Punct::new('!', Spacing::Alone)),
+        TokenTree::from(Group::new(Delimiter::Parenthesis, TokenTree::from(s).into())),
+    ])
+}
diff --git a/tests/ui/fmt/indoc-issue-106408.rs b/tests/ui/fmt/indoc-issue-106408.rs
new file mode 100644 (file)
index 0000000..e4e3093
--- /dev/null
@@ -0,0 +1,9 @@
+// aux-build:format-string-proc-macro.rs
+// check-pass
+
+extern crate format_string_proc_macro;
+
+fn main() {
+    let a = 0;
+    format_string_proc_macro::capture_a_with_prepended_space_preserve_span!("{a}");
+}
index 44642a10fc076d3c0dfd2bbee21ad09942ebb5b7..bb741c0ef93fa8bf0d523f610c767200256fdece 100644 (file)
@@ -1,10 +1,15 @@
 // aux-build:format-string-proc-macro.rs
+// check-fail
+// known-bug: #106191
+// unset-rustc-env:RUST_BACKTRACE
+// had to be reverted
+// error-pattern:internal compiler error
+// failure-status:101
+// dont-check-compiler-stderr
 
 extern crate format_string_proc_macro;
 
 fn main() {
     format_string_proc_macro::respan_to_invalid_format_literal!("¡");
-    //~^ ERROR invalid format string: expected `'}'` but string was terminated
     format_args!(r#concat!("¡        {"));
-    //~^ ERROR invalid format string: expected `'}'` but string was terminated
 }
index 73a3af65a3849dbce8754f03987a89fc49bb0343..16717f42253d6464fd77914e2136d012d5e36a27 100644 (file)
@@ -1,19 +1,2 @@
-error: invalid format string: expected `'}'` but string was terminated
-  --> $DIR/respanned-literal-issue-106191.rs:6:65
-   |
-LL |     format_string_proc_macro::respan_to_invalid_format_literal!("¡");
-   |                                                                 ^^^ expected `'}'` in format string
-   |
-   = note: if you intended to print `{`, you can escape it using `{{`
-
-error: invalid format string: expected `'}'` but string was terminated
-  --> $DIR/respanned-literal-issue-106191.rs:8:18
-   |
-LL |     format_args!(r#concat!("¡        {"));
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^ expected `'}'` in format string
-   |
-   = note: if you intended to print `{`, you can escape it using `{{`
-   = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 2 previous errors
-
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  query stack during panic:
+end of query stack
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 66f22bf31fc40696666afd30baf57f7d2b0e8a59..7211367afeee6fe3e4f8ab32a515f0dde3798662 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // run-pass
 // Regression test for broken MIR error (#61442)
 // Due to the two possible evaluation orders for
diff --git a/tests/ui/generator/auto-trait-regions.drop_tracking.stderr b/tests/ui/generator/auto-trait-regions.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..165748d
--- /dev/null
@@ -0,0 +1,47 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/auto-trait-regions.rs:48:24
+   |
+LL |         let a = A(&mut true, &mut true, No);
+   |                        ^^^^                - temporary value is freed at the end of this statement
+   |                        |
+   |                        creates a temporary value which is freed while still in use
+...
+LL |         assert_foo(a);
+   |                    - borrow later used here
+   |
+   = note: consider using a `let` binding to create a longer lived value
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/auto-trait-regions.rs:48:35
+   |
+LL |         let a = A(&mut true, &mut true, No);
+   |                                   ^^^^     - temporary value is freed at the end of this statement
+   |                                   |
+   |                                   creates a temporary value which is freed while still in use
+...
+LL |         assert_foo(a);
+   |                    - borrow later used here
+   |
+   = note: consider using a `let` binding to create a longer lived value
+
+error: implementation of `Foo` is not general enough
+  --> $DIR/auto-trait-regions.rs:34:5
+   |
+LL |     assert_foo(gen);
+   |     ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`...
+   = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef`
+
+error: implementation of `Foo` is not general enough
+  --> $DIR/auto-trait-regions.rs:54:5
+   |
+LL |     assert_foo(gen);
+   |     ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/generator/auto-trait-regions.drop_tracking_mir.stderr b/tests/ui/generator/auto-trait-regions.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..165748d
--- /dev/null
@@ -0,0 +1,47 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/auto-trait-regions.rs:48:24
+   |
+LL |         let a = A(&mut true, &mut true, No);
+   |                        ^^^^                - temporary value is freed at the end of this statement
+   |                        |
+   |                        creates a temporary value which is freed while still in use
+...
+LL |         assert_foo(a);
+   |                    - borrow later used here
+   |
+   = note: consider using a `let` binding to create a longer lived value
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/auto-trait-regions.rs:48:35
+   |
+LL |         let a = A(&mut true, &mut true, No);
+   |                                   ^^^^     - temporary value is freed at the end of this statement
+   |                                   |
+   |                                   creates a temporary value which is freed while still in use
+...
+LL |         assert_foo(a);
+   |                    - borrow later used here
+   |
+   = note: consider using a `let` binding to create a longer lived value
+
+error: implementation of `Foo` is not general enough
+  --> $DIR/auto-trait-regions.rs:34:5
+   |
+LL |     assert_foo(gen);
+   |     ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`...
+   = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef`
+
+error: implementation of `Foo` is not general enough
+  --> $DIR/auto-trait-regions.rs:54:5
+   |
+LL |     assert_foo(gen);
+   |     ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/generator/auto-trait-regions.no_drop_tracking.stderr b/tests/ui/generator/auto-trait-regions.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..165748d
--- /dev/null
@@ -0,0 +1,47 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/auto-trait-regions.rs:48:24
+   |
+LL |         let a = A(&mut true, &mut true, No);
+   |                        ^^^^                - temporary value is freed at the end of this statement
+   |                        |
+   |                        creates a temporary value which is freed while still in use
+...
+LL |         assert_foo(a);
+   |                    - borrow later used here
+   |
+   = note: consider using a `let` binding to create a longer lived value
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/auto-trait-regions.rs:48:35
+   |
+LL |         let a = A(&mut true, &mut true, No);
+   |                                   ^^^^     - temporary value is freed at the end of this statement
+   |                                   |
+   |                                   creates a temporary value which is freed while still in use
+...
+LL |         assert_foo(a);
+   |                    - borrow later used here
+   |
+   = note: consider using a `let` binding to create a longer lived value
+
+error: implementation of `Foo` is not general enough
+  --> $DIR/auto-trait-regions.rs:34:5
+   |
+LL |     assert_foo(gen);
+   |     ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`...
+   = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef`
+
+error: implementation of `Foo` is not general enough
+  --> $DIR/auto-trait-regions.rs:54:5
+   |
+LL |     assert_foo(gen);
+   |     ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
index ea4b0d554cde19910db9d16c4bd34b0d5f4249f1..fd13e41319f01be565189006571fc5ed7af0019f 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 #![feature(generators)]
 #![feature(auto_traits)]
 #![feature(negative_impls)]
index 0b1f34aeb96bd52172833446ece6a7cc0c11c3b3..165748d44305a733353549dbe6ba28d15de56a46 100644 (file)
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/auto-trait-regions.rs:45:24
+  --> $DIR/auto-trait-regions.rs:48:24
    |
 LL |         let a = A(&mut true, &mut true, No);
    |                        ^^^^                - temporary value is freed at the end of this statement
@@ -12,7 +12,7 @@ LL |         assert_foo(a);
    = note: consider using a `let` binding to create a longer lived value
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/auto-trait-regions.rs:45:35
+  --> $DIR/auto-trait-regions.rs:48:35
    |
 LL |         let a = A(&mut true, &mut true, No);
    |                                   ^^^^     - temporary value is freed at the end of this statement
@@ -25,7 +25,7 @@ LL |         assert_foo(a);
    = note: consider using a `let` binding to create a longer lived value
 
 error: implementation of `Foo` is not general enough
-  --> $DIR/auto-trait-regions.rs:31:5
+  --> $DIR/auto-trait-regions.rs:34:5
    |
 LL |     assert_foo(gen);
    |     ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
@@ -34,7 +34,7 @@ LL |     assert_foo(gen);
    = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef`
 
 error: implementation of `Foo` is not general enough
-  --> $DIR/auto-trait-regions.rs:51:5
+  --> $DIR/auto-trait-regions.rs:54:5
    |
 LL |     assert_foo(gen);
    |     ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
diff --git a/tests/ui/generator/borrowing.drop_tracking.stderr b/tests/ui/generator/borrowing.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..96e3c32
--- /dev/null
@@ -0,0 +1,31 @@
+error[E0597]: `a` does not live long enough
+  --> $DIR/borrowing.rs:13:33
+   |
+LL |     let _b = {
+   |         -- borrow later stored here
+LL |         let a = 3;
+LL |         Pin::new(&mut || yield &a).resume(())
+   |                       --        ^ borrowed value does not live long enough
+   |                       |
+   |                       value captured here by generator
+LL |
+LL |     };
+   |     - `a` dropped here while still borrowed
+
+error[E0597]: `a` does not live long enough
+  --> $DIR/borrowing.rs:20:20
+   |
+LL |     let _b = {
+   |         -- borrow later stored here
+LL |         let a = 3;
+LL |         || {
+   |         -- value captured here by generator
+LL |             yield &a
+   |                    ^ borrowed value does not live long enough
+...
+LL |     };
+   |     - `a` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/generator/borrowing.drop_tracking_mir.stderr b/tests/ui/generator/borrowing.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..8fbad27
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0597]: `a` does not live long enough
+  --> $DIR/borrowing.rs:13:33
+   |
+LL |         Pin::new(&mut || yield &a).resume(())
+   |                       ----------^
+   |                       |         |
+   |                       |         borrowed value does not live long enough
+   |                       value captured here by generator
+   |                       a temporary with access to the borrow is created here ...
+LL |
+LL |     };
+   |     -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for generator
+   |     |
+   |     `a` dropped here while still borrowed
+   |
+   = 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
+help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
+   |
+LL |         let x = Pin::new(&mut || yield &a).resume(()); x
+   |         +++++++                                      +++
+
+error[E0597]: `a` does not live long enough
+  --> $DIR/borrowing.rs:20:20
+   |
+LL |     let _b = {
+   |         -- borrow later stored here
+LL |         let a = 3;
+LL |         || {
+   |         -- value captured here by generator
+LL |             yield &a
+   |                    ^ borrowed value does not live long enough
+...
+LL |     };
+   |     - `a` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/generator/borrowing.no_drop_tracking.stderr b/tests/ui/generator/borrowing.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..96e3c32
--- /dev/null
@@ -0,0 +1,31 @@
+error[E0597]: `a` does not live long enough
+  --> $DIR/borrowing.rs:13:33
+   |
+LL |     let _b = {
+   |         -- borrow later stored here
+LL |         let a = 3;
+LL |         Pin::new(&mut || yield &a).resume(())
+   |                       --        ^ borrowed value does not live long enough
+   |                       |
+   |                       value captured here by generator
+LL |
+LL |     };
+   |     - `a` dropped here while still borrowed
+
+error[E0597]: `a` does not live long enough
+  --> $DIR/borrowing.rs:20:20
+   |
+LL |     let _b = {
+   |         -- borrow later stored here
+LL |         let a = 3;
+LL |         || {
+   |         -- value captured here by generator
+LL |             yield &a
+   |                    ^ borrowed value does not live long enough
+...
+LL |     };
+   |     - `a` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
index d36592583cdc598c70fe0f87b6f9c149d5b5c881..29f39437f8f554ce078e523377833f3924214dfb 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+
 #![feature(generators, generator_trait)]
 
 use std::ops::Generator;
index 38e1ace8c4efbc358033fce0f69245851ee47dd6..96e3c327f8b31904864d4af6e44eee751821d79a 100644 (file)
@@ -1,5 +1,5 @@
 error[E0597]: `a` does not live long enough
-  --> $DIR/borrowing.rs:9:33
+  --> $DIR/borrowing.rs:13:33
    |
 LL |     let _b = {
    |         -- borrow later stored here
@@ -13,7 +13,7 @@ LL |     };
    |     - `a` dropped here while still borrowed
 
 error[E0597]: `a` does not live long enough
-  --> $DIR/borrowing.rs:16:20
+  --> $DIR/borrowing.rs:20:20
    |
 LL |     let _b = {
    |         -- borrow later stored here
diff --git a/tests/ui/generator/drop-tracking-parent-expression.drop_tracking.stderr b/tests/ui/generator/drop-tracking-parent-expression.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..c07906e
--- /dev/null
@@ -0,0 +1,128 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `derived_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `derived_drop::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `significant_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `significant_drop::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `insignificant_dtor::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/generator/drop-tracking-parent-expression.drop_tracking_mir.stderr b/tests/ui/generator/drop-tracking-parent-expression.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..35698a9
--- /dev/null
@@ -0,0 +1,122 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:27:13
+   |
+LL |               assert_send(g);
+   |               ^^^^^^^^^^^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `derived_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `derived_drop::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:27:13
+   |
+LL |               assert_send(g);
+   |               ^^^^^^^^^^^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `significant_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `significant_drop::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:27:13
+   |
+LL |               assert_send(g);
+   |               ^^^^^^^^^^^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `insignificant_dtor::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/generator/drop-tracking-parent-expression.no_drop_tracking.stderr b/tests/ui/generator/drop-tracking-parent-expression.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..1a05bfe
--- /dev/null
@@ -0,0 +1,334 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `copy::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `copy::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:40:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `copy::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:38:22
+   |
+LL |               let g = move || match drop($name::Client::default()) {
+   |                                          ------------------------ has type `copy::Client` which is not `Send`
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `derived_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `derived_drop::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:40:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `derived_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:38:22
+   |
+LL |               let g = move || match drop($name::Client::default()) {
+   |                                          ------------------------ has type `derived_drop::Client` which is not `Send`
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `significant_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `significant_drop::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:40:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `significant_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:38:22
+   |
+LL |               let g = move || match drop($name::Client::default()) {
+   |                                          ------------------------ has type `significant_drop::Client` which is not `Send`
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `insignificant_dtor::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-tracking-parent-expression.rs:40:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-tracking-parent-expression.rs:38:22
+   |
+LL |               let g = move || match drop($name::Client::default()) {
+   |                                          ------------------------ has type `insignificant_dtor::Client` which is not `Send`
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/drop-tracking-parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 8 previous errors
+
index d40f1b8f64d4aa587b9df5591f07702b23937d11..ed9ac6d11adb1d787dd28ea184a0fd37753cd559 100644 (file)
@@ -1,4 +1,7 @@
-// compile-flags: -Zdrop-tracking
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+
 #![feature(generators, negative_impls, rustc_attrs)]
 
 macro_rules! type_combinations {
@@ -18,13 +21,14 @@ impl !Send for Client {}
             let g = move || match drop($name::Client { ..$name::Client::default() }) {
             //~^ `significant_drop::Client` which is not `Send`
             //~| `insignificant_dtor::Client` which is not `Send`
-            //~| `derived_drop::Client` which is not `Send`
+            //[no_drop_tracking,drop_tracking]~| `derived_drop::Client` which is not `Send`
                 _ => yield,
             };
             assert_send(g);
             //~^ ERROR cannot be sent between threads
             //~| ERROR cannot be sent between threads
             //~| ERROR cannot be sent between threads
+            //[no_drop_tracking]~| ERROR cannot be sent between threads
         }
 
         // Simple owned value. This works because the Client is considered moved into `drop`,
@@ -34,6 +38,10 @@ impl !Send for Client {}
                 _ => yield,
             };
             assert_send(g);
+            //[no_drop_tracking]~^ ERROR cannot be sent between threads
+            //[no_drop_tracking]~| ERROR cannot be sent between threads
+            //[no_drop_tracking]~| ERROR cannot be sent between threads
+            //[no_drop_tracking]~| ERROR cannot be sent between threads
         }
     )* }
 }
diff --git a/tests/ui/generator/drop-tracking-parent-expression.stderr b/tests/ui/generator/drop-tracking-parent-expression.stderr
deleted file mode 100644 (file)
index fbf5d6e..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-error: generator cannot be sent between threads safely
-  --> $DIR/drop-tracking-parent-expression.rs:24:25
-   |
-LL |               assert_send(g);
-   |                           ^ generator is not `Send`
-...
-LL | /     type_combinations!(
-LL | |         // OK
-LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
-LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
-...  |
-LL | |         };
-LL | |     );
-   | |_____- in this macro invocation
-   |
-   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `derived_drop::Client`
-note: generator is not `Send` as this value is used across a yield
-  --> $DIR/drop-tracking-parent-expression.rs:22:22
-   |
-LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
-   |                                                            ------------------------ has type `derived_drop::Client` which is not `Send`
-...
-LL |                   _ => yield,
-   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
-LL |               };
-   |               - `$name::Client::default()` is later dropped here
-...
-LL | /     type_combinations!(
-LL | |         // OK
-LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
-LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
-...  |
-LL | |         };
-LL | |     );
-   | |_____- in this macro invocation
-note: required by a bound in `assert_send`
-  --> $DIR/drop-tracking-parent-expression.rs:41:19
-   |
-LL | fn assert_send<T: Send>(_thing: T) {}
-   |                   ^^^^ required by this bound in `assert_send`
-   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: generator cannot be sent between threads safely
-  --> $DIR/drop-tracking-parent-expression.rs:24:25
-   |
-LL |               assert_send(g);
-   |                           ^ generator is not `Send`
-...
-LL | /     type_combinations!(
-LL | |         // OK
-LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
-LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
-...  |
-LL | |         };
-LL | |     );
-   | |_____- in this macro invocation
-   |
-   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `significant_drop::Client`
-note: generator is not `Send` as this value is used across a yield
-  --> $DIR/drop-tracking-parent-expression.rs:22:22
-   |
-LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
-   |                                                            ------------------------ has type `significant_drop::Client` which is not `Send`
-...
-LL |                   _ => yield,
-   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
-LL |               };
-   |               - `$name::Client::default()` is later dropped here
-...
-LL | /     type_combinations!(
-LL | |         // OK
-LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
-LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
-...  |
-LL | |         };
-LL | |     );
-   | |_____- in this macro invocation
-note: required by a bound in `assert_send`
-  --> $DIR/drop-tracking-parent-expression.rs:41:19
-   |
-LL | fn assert_send<T: Send>(_thing: T) {}
-   |                   ^^^^ required by this bound in `assert_send`
-   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: generator cannot be sent between threads safely
-  --> $DIR/drop-tracking-parent-expression.rs:24:25
-   |
-LL |               assert_send(g);
-   |                           ^ generator is not `Send`
-...
-LL | /     type_combinations!(
-LL | |         // OK
-LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
-LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
-...  |
-LL | |         };
-LL | |     );
-   | |_____- in this macro invocation
-   |
-   = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client`
-note: generator is not `Send` as this value is used across a yield
-  --> $DIR/drop-tracking-parent-expression.rs:22:22
-   |
-LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
-   |                                                            ------------------------ has type `insignificant_dtor::Client` which is not `Send`
-...
-LL |                   _ => yield,
-   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
-LL |               };
-   |               - `$name::Client::default()` is later dropped here
-...
-LL | /     type_combinations!(
-LL | |         // OK
-LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
-LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
-...  |
-LL | |         };
-LL | |     );
-   | |_____- in this macro invocation
-note: required by a bound in `assert_send`
-  --> $DIR/drop-tracking-parent-expression.rs:41:19
-   |
-LL | fn assert_send<T: Send>(_thing: T) {}
-   |                   ^^^^ required by this bound in `assert_send`
-   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 3 previous errors
-
index 646365e4359016eb958bc796b92512318fadc07a..cbc291701cbc9d9a67ea18f269b2b89b54eaaa88 100644 (file)
@@ -1,6 +1,8 @@
 // build-pass
 // edition:2018
-// compile-flags: -Zdrop-tracking
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 
 #![feature(generators)]
 
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
 ...
diff --git a/tests/ui/generator/issue-105084.drop_tracking_mir.stderr b/tests/ui/generator/issue-105084.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..cfc0cf7
--- /dev/null
@@ -0,0 +1,51 @@
+error[E0382]: borrow of moved value: `g`
+  --> $DIR/issue-105084.rs:44:14
+   |
+LL |     let mut g = || {
+   |         ----- move occurs because `g` has type `[generator@$DIR/issue-105084.rs:22:17: 22:19]`, which does not implement the `Copy` trait
+...
+LL |     let mut h = copy(g);
+   |                      - value moved here
+...
+LL |     Pin::new(&mut g).resume(());
+   |              ^^^^^^ value borrowed here after move
+   |
+note: consider changing this parameter type in function `copy` to borrow instead if owning the value isn't necessary
+  --> $DIR/issue-105084.rs:17:21
+   |
+LL | fn copy<T: Copy>(x: T) -> T {
+   |    ----             ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let mut h = copy(g.clone());
+   |                       ++++++++
+
+error[E0277]: the trait bound `Box<(i32, ())>: Copy` is not satisfied in `[generator@$DIR/issue-105084.rs:22:17: 22:19]`
+  --> $DIR/issue-105084.rs:38:17
+   |
+LL |     let mut g = || {
+   |                 -- within this `[generator@$DIR/issue-105084.rs:22:17: 22:19]`
+...
+LL |     let mut h = copy(g);
+   |                 ^^^^ within `[generator@$DIR/issue-105084.rs:22:17: 22:19]`, the trait `Copy` is not implemented for `Box<(i32, ())>`
+   |
+note: generator does not implement `Copy` as this value is used across a yield
+  --> $DIR/issue-105084.rs:28:25
+   |
+LL |         let t = box (5, yield);
+   |                 --------^^^^^-
+   |                 |       |
+   |                 |       yield occurs here, with `box (5, yield)` maybe used later
+   |                 has type `Box<(i32, ())>` which does not implement `Copy`
+note: required by a bound in `copy`
+  --> $DIR/issue-105084.rs:17:12
+   |
+LL | fn copy<T: Copy>(x: T) -> T {
+   |            ^^^^ required by this bound in `copy`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0382.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/generator/issue-105084.rs b/tests/ui/generator/issue-105084.rs
new file mode 100644 (file)
index 0000000..7c9a97b
--- /dev/null
@@ -0,0 +1,49 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+// [no_drop_tracking] known-bug: #105084
+// [no_drop_tracking] check-pass
+// [drop_tracking] known-bug: #105084
+// [drop_tracking] check-pass
+
+#![feature(generators)]
+#![feature(generator_clone)]
+#![feature(generator_trait)]
+#![feature(box_syntax)]
+
+use std::ops::Generator;
+use std::pin::Pin;
+
+fn copy<T: Copy>(x: T) -> T {
+    x
+}
+
+fn main() {
+    let mut g = || {
+        // This is desuraged as 4 stages:
+        // - allocate a `*mut u8` with `exchange_malloc`;
+        // - create a Box that is ignored for trait computations;
+        // - compute fields (and yields);
+        // - assign to `t`.
+        let t = box (5, yield);
+        drop(t);
+    };
+
+    // Allocate the temporary box.
+    Pin::new(&mut g).resume(());
+
+    // The temporary box is in generator locals.
+    // As it is not taken into account for trait computation,
+    // the generator is `Copy`.
+    let mut h = copy(g);
+    //[drop_tracking_mir]~^ ERROR the trait bound `Box<(i32, ())>: Copy` is not satisfied in
+
+    // We now have 2 boxes with the same backing allocation:
+    // one inside `g` and one inside `h`.
+    // Proceed and drop `t` in `g`.
+    Pin::new(&mut g).resume(());
+    //[drop_tracking_mir]~^ ERROR borrow of moved value: `g`
+
+    // Proceed and drop `t` in `h` -> double free!
+    Pin::new(&mut h).resume(());
+}
diff --git a/tests/ui/generator/issue-57017.no_drop_tracking.stderr b/tests/ui/generator/issue-57017.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..06d2d23
--- /dev/null
@@ -0,0 +1,248 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/issue-57017.rs:31:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+LL | |         significant_drop => {
+...  |
+LL | |         }
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: the trait `Sync` is not implemented for `copy::unsync::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/issue-57017.rs:29:28
+   |
+LL |               let g = move || match drop(&$name::unsync::Client::default()) {
+   |                                          --------------------------------- has type `&copy::unsync::Client` which is not `Send`
+LL |                   _status => yield,
+   |                              ^^^^^ yield occurs here, with `&$name::unsync::Client::default()` maybe used later
+LL |               };
+   |               - `&$name::unsync::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+LL | |         significant_drop => {
+...  |
+LL | |         }
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/issue-57017.rs:51:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/issue-57017.rs:43:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+LL | |         significant_drop => {
+...  |
+LL | |         }
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/issue-57017.rs:40:21: 40:28]`, the trait `Send` is not implemented for `copy::unsend::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/issue-57017.rs:41:28
+   |
+LL |               let g = move || match drop($name::unsend::Client::default()) {
+   |                                          -------------------------------- has type `copy::unsend::Client` which is not `Send`
+LL |                   _status => yield,
+   |                              ^^^^^ yield occurs here, with `$name::unsend::Client::default()` maybe used later
+LL |               };
+   |               - `$name::unsend::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+LL | |         significant_drop => {
+...  |
+LL | |         }
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/issue-57017.rs:51:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/issue-57017.rs:31:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+LL | |         significant_drop => {
+...  |
+LL | |         }
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: the trait `Sync` is not implemented for `derived_drop::unsync::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/issue-57017.rs:29:28
+   |
+LL |               let g = move || match drop(&$name::unsync::Client::default()) {
+   |                                          --------------------------------- has type `&derived_drop::unsync::Client` which is not `Send`
+LL |                   _status => yield,
+   |                              ^^^^^ yield occurs here, with `&$name::unsync::Client::default()` maybe used later
+LL |               };
+   |               - `&$name::unsync::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+LL | |         significant_drop => {
+...  |
+LL | |         }
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/issue-57017.rs:51:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/issue-57017.rs:43:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+LL | |         significant_drop => {
+...  |
+LL | |         }
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/issue-57017.rs:40:21: 40:28]`, the trait `Send` is not implemented for `derived_drop::unsend::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/issue-57017.rs:41:28
+   |
+LL |               let g = move || match drop($name::unsend::Client::default()) {
+   |                                          -------------------------------- has type `derived_drop::unsend::Client` which is not `Send`
+LL |                   _status => yield,
+   |                              ^^^^^ yield occurs here, with `$name::unsend::Client::default()` maybe used later
+LL |               };
+   |               - `$name::unsend::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+LL | |         significant_drop => {
+...  |
+LL | |         }
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/issue-57017.rs:51:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/issue-57017.rs:31:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+LL | |         significant_drop => {
+...  |
+LL | |         }
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: the trait `Sync` is not implemented for `significant_drop::unsync::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/issue-57017.rs:29:28
+   |
+LL |               let g = move || match drop(&$name::unsync::Client::default()) {
+   |                                          --------------------------------- has type `&significant_drop::unsync::Client` which is not `Send`
+LL |                   _status => yield,
+   |                              ^^^^^ yield occurs here, with `&$name::unsync::Client::default()` maybe used later
+LL |               };
+   |               - `&$name::unsync::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+LL | |         significant_drop => {
+...  |
+LL | |         }
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/issue-57017.rs:51:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/issue-57017.rs:43:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+LL | |         significant_drop => {
+...  |
+LL | |         }
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/issue-57017.rs:40:21: 40:28]`, the trait `Send` is not implemented for `significant_drop::unsend::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/issue-57017.rs:41:28
+   |
+LL |               let g = move || match drop($name::unsend::Client::default()) {
+   |                                          -------------------------------- has type `significant_drop::unsend::Client` which is not `Send`
+LL |                   _status => yield,
+   |                              ^^^^^ yield occurs here, with `$name::unsend::Client::default()` maybe used later
+LL |               };
+   |               - `$name::unsend::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+LL | |         significant_drop => {
+...  |
+LL | |         }
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/issue-57017.rs:51:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
+
index c0bde3b4473e10ea0cc7d865e141b1503064e4b2..03b00ac99ad221fd447eefec7af003d9adf37f63 100644 (file)
@@ -1,5 +1,9 @@
-// build-pass
-// compile-flags: -Zdrop-tracking
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+// [drop_tracking] build-pass
+// [drop_tracking_mir] build-pass
+
 #![feature(generators, negative_impls)]
 
 macro_rules! type_combinations {
@@ -25,6 +29,9 @@ impl !Send for Client {}
                 _status => yield,
             };
             assert_send(g);
+            //[no_drop_tracking]~^ ERROR generator cannot be sent between threads safely
+            //[no_drop_tracking]~| ERROR generator cannot be sent between threads safely
+            //[no_drop_tracking]~| ERROR generator cannot be sent between threads safely
         }
 
         // This tests that `Client` is properly considered to be dropped after moving it into the
@@ -34,6 +41,9 @@ impl !Send for Client {}
                 _status => yield,
             };
             assert_send(g);
+            //[no_drop_tracking]~^ ERROR generator cannot be sent between threads safely
+            //[no_drop_tracking]~| ERROR generator cannot be sent between threads safely
+            //[no_drop_tracking]~| ERROR generator cannot be sent between threads safely
         }
     )* }
 }
diff --git a/tests/ui/generator/issue-57478.no_drop_tracking.stderr b/tests/ui/generator/issue-57478.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..612dd9c
--- /dev/null
@@ -0,0 +1,31 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/issue-57478.rs:13:17
+   |
+LL |       assert_send(|| {
+   |  _________________^
+LL | |
+LL | |         let guard = Foo;
+LL | |         drop(guard);
+LL | |         yield;
+LL | |     })
+   | |_____^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/issue-57478.rs:13:17: 13:19]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/issue-57478.rs:17:9
+   |
+LL |         let guard = Foo;
+   |             ----- has type `Foo` which is not `Send`
+LL |         drop(guard);
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `guard` maybe used later
+LL |     })
+   |     - `guard` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/issue-57478.rs:21:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to previous error
+
index 91407ea1844f54922c084cb77f34619928f7d1e9..3c23b5992710e2bceb3a3b5903b6add9bcdb306f 100644 (file)
@@ -1,5 +1,8 @@
-// check-pass
-// compile-flags: -Zdrop-tracking
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+// [drop_tracking] check-pass
+// [drop_tracking_mir] check-pass
 
 #![feature(negative_impls, generators)]
 
@@ -8,6 +11,7 @@ impl !Send for Foo {}
 
 fn main() {
     assert_send(|| {
+        //[no_drop_tracking]~^ ERROR generator cannot be sent between threads safely
         let guard = Foo;
         drop(guard);
         yield;
diff --git a/tests/ui/generator/issue-68112.drop_tracking.stderr b/tests/ui/generator/issue-68112.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..282eac1
--- /dev/null
@@ -0,0 +1,66 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/issue-68112.rs:43:18
+   |
+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:39:9
+   |
+LL |         let _non_send_gen = make_non_send_generator();
+   |             ------------- has type `impl Generator<Return = Arc<RefCell<i32>>>` which is not `Send`
+LL |
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
+...
+LL |     };
+   |     - `_non_send_gen` is later dropped here
+note: required by a bound in `require_send`
+  --> $DIR/issue-68112.rs:25:25
+   |
+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:67:18
+   |
+LL |     require_send(send_gen);
+   |     ------------ ^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
+   |     |
+   |     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:52:5
+   |
+LL |     || {
+   |     ^^
+note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>`
+  --> $DIR/issue-68112.rs:49: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:57: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:63:20
+   |
+LL |     let send_gen = || {
+   |                    ^^
+note: required by a bound in `require_send`
+  --> $DIR/issue-68112.rs:25:25
+   |
+LL | fn require_send(_: impl Send) {}
+   |                         ^^^^ required by this bound in `require_send`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/generator/issue-68112.drop_tracking_mir.stderr b/tests/ui/generator/issue-68112.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..a83522b
--- /dev/null
@@ -0,0 +1,61 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/issue-68112.rs:43:5
+   |
+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:39:9
+   |
+LL |         let _non_send_gen = make_non_send_generator();
+   |             ------------- has type `impl Generator<Return = Arc<RefCell<i32>>>` which is not `Send`
+LL |
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
+note: required by a bound in `require_send`
+  --> $DIR/issue-68112.rs:25:25
+   |
+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:67:5
+   |
+LL |     require_send(send_gen);
+   |     ^^^^^^^^^^^^ `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 for `Arc<RefCell<i32>>` to implement `Send`
+note: required because it's used within this generator
+  --> $DIR/issue-68112.rs:52:5
+   |
+LL |     || {
+   |     ^^
+note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>`
+  --> $DIR/issue-68112.rs:49: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:57: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:63:20
+   |
+LL |     let send_gen = || {
+   |                    ^^
+note: required by a bound in `require_send`
+  --> $DIR/issue-68112.rs:25:25
+   |
+LL | fn require_send(_: impl Send) {}
+   |                         ^^^^ required by this bound in `require_send`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/generator/issue-68112.no_drop_tracking.stderr b/tests/ui/generator/issue-68112.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..282eac1
--- /dev/null
@@ -0,0 +1,66 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/issue-68112.rs:43:18
+   |
+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:39:9
+   |
+LL |         let _non_send_gen = make_non_send_generator();
+   |             ------------- has type `impl Generator<Return = Arc<RefCell<i32>>>` which is not `Send`
+LL |
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
+...
+LL |     };
+   |     - `_non_send_gen` is later dropped here
+note: required by a bound in `require_send`
+  --> $DIR/issue-68112.rs:25:25
+   |
+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:67:18
+   |
+LL |     require_send(send_gen);
+   |     ------------ ^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
+   |     |
+   |     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:52:5
+   |
+LL |     || {
+   |     ^^
+note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>`
+  --> $DIR/issue-68112.rs:49: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:57: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:63:20
+   |
+LL |     let send_gen = || {
+   |                    ^^
+note: required by a bound in `require_send`
+  --> $DIR/issue-68112.rs:25:25
+   |
+LL | fn require_send(_: impl Send) {}
+   |                         ^^^^ required by this bound in `require_send`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 21026f45cb823375f9cc94400a0aed20da7ef085..48b53b7693d41f5e83012b36c17e8e9cfd5d8e8f 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 #![feature(generators, generator_trait)]
 
 use std::{
@@ -8,7 +11,7 @@
 };
 
 pub struct Ready<T>(Option<T>);
-impl<T> Generator<()> for Ready<T> {
+impl<T: Unpin> Generator<()> for Ready<T> {
     type Return = T;
     type Yield = ();
     fn resume(mut self: Pin<&mut Self>, _args: ()) -> GeneratorState<(), T> {
@@ -36,10 +39,11 @@ fn test1() {
         yield;
         //~^ NOTE yield occurs here
         //~| NOTE value is used across a yield
-    }; //~ NOTE later dropped here
+    }; //[no_drop_tracking,drop_tracking]~ NOTE later dropped here
     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> {
@@ -64,8 +68,9 @@ fn test2() {
     //~^ ERROR `RefCell<i32>` cannot be shared between threads safely
     //~| NOTE `RefCell<i32>` cannot be shared between threads safely
     //~| NOTE required for
-    //~| NOTE required by a bound introduced by this call
+    //[no_drop_tracking,drop_tracking]~| NOTE required by a bound introduced by this call
     //~| NOTE captures the following types
+    //~| NOTE use `std::sync::RwLock` instead
 }
 
 fn main() {}
diff --git a/tests/ui/generator/issue-68112.stderr b/tests/ui/generator/issue-68112.stderr
deleted file mode 100644 (file)
index eb99d42..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-error: generator cannot be sent between threads safely
-  --> $DIR/issue-68112.rs:40:18
-   |
-LL |     require_send(send_gen);
-   |                  ^^^^^^^^ generator is not `Send`
-   |
-   = help: the trait `Sync` is not implemented for `RefCell<i32>`
-note: generator is not `Send` as this value is used across a yield
-  --> $DIR/issue-68112.rs:36:9
-   |
-LL |         let _non_send_gen = make_non_send_generator();
-   |             ------------- has type `impl Generator<Return = Arc<RefCell<i32>>>` which is not `Send`
-LL |
-LL |         yield;
-   |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
-...
-LL |     };
-   |     - `_non_send_gen` is later dropped here
-note: required by a bound in `require_send`
-  --> $DIR/issue-68112.rs:22:25
-   |
-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
-   |
-LL |     require_send(send_gen);
-   |     ------------ ^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
-   |     |
-   |     required by a bound introduced by this call
-   |
-   = help: the trait `Sync` is not implemented for `RefCell<i32>`
-   = note: required for `Arc<RefCell<i32>>` to implement `Send`
-note: required because it's used within this generator
-  --> $DIR/issue-68112.rs:48:5
-   |
-LL |     || {
-   |     ^^
-note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>`
-  --> $DIR/issue-68112.rs:45: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
-   |
-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
-   |
-LL |     let send_gen = || {
-   |                    ^^
-note: required by a bound in `require_send`
-  --> $DIR/issue-68112.rs:22:25
-   |
-LL | fn require_send(_: impl Send) {}
-   |                         ^^^^ required by this bound in `require_send`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
index 92305609c835c6248b50d13477d9fd0c0cec387a..8d3f7c62f393611abfc387bd8192bf4a114750ea 100644 (file)
@@ -1,6 +1,8 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2021
 // run-pass
-// compile-flags: -Zdrop-tracking
 
 #![feature(never_type)]
 
diff --git a/tests/ui/generator/not-send-sync.drop_tracking.stderr b/tests/ui/generator/not-send-sync.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..718fd42
--- /dev/null
@@ -0,0 +1,60 @@
+error: generator cannot be shared between threads safely
+  --> $DIR/not-send-sync.rs:17:17
+   |
+LL |       assert_sync(|| {
+   |  _________________^
+LL | |
+LL | |         let a = NotSync;
+LL | |         yield;
+LL | |         drop(a);
+LL | |     });
+   | |_____^ generator is not `Sync`
+   |
+   = help: within `[generator@$DIR/not-send-sync.rs:17:17: 17:19]`, the trait `Sync` is not implemented for `NotSync`
+note: generator is not `Sync` as this value is used across a yield
+  --> $DIR/not-send-sync.rs:20:9
+   |
+LL |         let a = NotSync;
+   |             - has type `NotSync` which is not `Sync`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+LL |         drop(a);
+LL |     });
+   |     - `a` is later dropped here
+note: required by a bound in `assert_sync`
+  --> $DIR/not-send-sync.rs:14:23
+   |
+LL |     fn assert_sync<T: Sync>(_: T) {}
+   |                       ^^^^ required by this bound in `assert_sync`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/not-send-sync.rs:24:17
+   |
+LL |       assert_send(|| {
+   |  _________________^
+LL | |
+LL | |         let a = NotSend;
+LL | |         yield;
+LL | |         drop(a);
+LL | |     });
+   | |_____^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/not-send-sync.rs:24:17: 24:19]`, the trait `Send` is not implemented for `NotSend`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/not-send-sync.rs:27:9
+   |
+LL |         let a = NotSend;
+   |             - has type `NotSend` which is not `Send`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+LL |         drop(a);
+LL |     });
+   |     - `a` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/not-send-sync.rs:15:23
+   |
+LL |     fn assert_send<T: Send>(_: T) {}
+   |                       ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/generator/not-send-sync.drop_tracking_mir.stderr b/tests/ui/generator/not-send-sync.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..66f01ae
--- /dev/null
@@ -0,0 +1,42 @@
+error: generator cannot be shared between threads safely
+  --> $DIR/not-send-sync.rs:17:5
+   |
+LL |     assert_sync(|| {
+   |     ^^^^^^^^^^^ generator is not `Sync`
+   |
+   = help: within `[generator@$DIR/not-send-sync.rs:17:17: 17:19]`, the trait `Sync` is not implemented for `NotSync`
+note: generator is not `Sync` as this value is used across a yield
+  --> $DIR/not-send-sync.rs:20:9
+   |
+LL |         let a = NotSync;
+   |             - has type `NotSync` which is not `Sync`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+note: required by a bound in `assert_sync`
+  --> $DIR/not-send-sync.rs:14:23
+   |
+LL |     fn assert_sync<T: Sync>(_: T) {}
+   |                       ^^^^ required by this bound in `assert_sync`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/not-send-sync.rs:24:5
+   |
+LL |     assert_send(|| {
+   |     ^^^^^^^^^^^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/not-send-sync.rs:24:17: 24:19]`, the trait `Send` is not implemented for `NotSend`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/not-send-sync.rs:27:9
+   |
+LL |         let a = NotSend;
+   |             - has type `NotSend` which is not `Send`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+note: required by a bound in `assert_send`
+  --> $DIR/not-send-sync.rs:15:23
+   |
+LL |     fn assert_send<T: Send>(_: T) {}
+   |                       ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/generator/not-send-sync.no_drop_tracking.stderr b/tests/ui/generator/not-send-sync.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..718fd42
--- /dev/null
@@ -0,0 +1,60 @@
+error: generator cannot be shared between threads safely
+  --> $DIR/not-send-sync.rs:17:17
+   |
+LL |       assert_sync(|| {
+   |  _________________^
+LL | |
+LL | |         let a = NotSync;
+LL | |         yield;
+LL | |         drop(a);
+LL | |     });
+   | |_____^ generator is not `Sync`
+   |
+   = help: within `[generator@$DIR/not-send-sync.rs:17:17: 17:19]`, the trait `Sync` is not implemented for `NotSync`
+note: generator is not `Sync` as this value is used across a yield
+  --> $DIR/not-send-sync.rs:20:9
+   |
+LL |         let a = NotSync;
+   |             - has type `NotSync` which is not `Sync`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+LL |         drop(a);
+LL |     });
+   |     - `a` is later dropped here
+note: required by a bound in `assert_sync`
+  --> $DIR/not-send-sync.rs:14:23
+   |
+LL |     fn assert_sync<T: Sync>(_: T) {}
+   |                       ^^^^ required by this bound in `assert_sync`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/not-send-sync.rs:24:17
+   |
+LL |       assert_send(|| {
+   |  _________________^
+LL | |
+LL | |         let a = NotSend;
+LL | |         yield;
+LL | |         drop(a);
+LL | |     });
+   | |_____^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/not-send-sync.rs:24:17: 24:19]`, the trait `Send` is not implemented for `NotSend`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/not-send-sync.rs:27:9
+   |
+LL |         let a = NotSend;
+   |             - has type `NotSend` which is not `Send`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+LL |         drop(a);
+LL |     });
+   |     - `a` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/not-send-sync.rs:15:23
+   |
+LL |     fn assert_send<T: Send>(_: T) {}
+   |                       ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 2 previous errors
+
index 8ca5565fb2ab551982a5143b50682bedee8f3919..8794db452b4651bfd51c14cef7973b51dda6284b 100644 (file)
@@ -1,6 +1,14 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 #![feature(generators)]
+#![feature(negative_impls)]
 
-use std::cell::Cell;
+struct NotSend;
+struct NotSync;
+
+impl !Send for NotSend {}
+impl !Sync for NotSync {}
 
 fn main() {
     fn assert_sync<T: Sync>(_: T) {}
@@ -8,14 +16,15 @@ fn assert_send<T: Send>(_: T) {}
 
     assert_sync(|| {
         //~^ ERROR: generator cannot be shared between threads safely
-        let a = Cell::new(2);
+        let a = NotSync;
         yield;
+        drop(a);
     });
 
-    let a = Cell::new(2);
     assert_send(|| {
-        //~^ ERROR: E0277
-        drop(&a);
+        //~^ ERROR: generator cannot be sent between threads safely
+        let a = NotSend;
         yield;
+        drop(a);
     });
 }
diff --git a/tests/ui/generator/not-send-sync.stderr b/tests/ui/generator/not-send-sync.stderr
deleted file mode 100644 (file)
index a821c57..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-error[E0277]: `Cell<i32>` cannot be shared between threads safely
-  --> $DIR/not-send-sync.rs:16:17
-   |
-LL |       assert_send(|| {
-   |  _____-----------_^
-   | |     |
-   | |     required by a bound introduced by this call
-LL | |
-LL | |         drop(&a);
-LL | |         yield;
-LL | |     });
-   | |_____^ `Cell<i32>` cannot be shared between threads safely
-   |
-   = help: the trait `Sync` is not implemented for `Cell<i32>`
-   = note: required for `&Cell<i32>` to implement `Send`
-note: required because it's used within this generator
-  --> $DIR/not-send-sync.rs:16:17
-   |
-LL |     assert_send(|| {
-   |                 ^^
-note: required by a bound in `assert_send`
-  --> $DIR/not-send-sync.rs:7:23
-   |
-LL |     fn assert_send<T: Send>(_: T) {}
-   |                       ^^^^ required by this bound in `assert_send`
-
-error: generator cannot be shared between threads safely
-  --> $DIR/not-send-sync.rs:9:17
-   |
-LL |       assert_sync(|| {
-   |  _________________^
-LL | |
-LL | |         let a = Cell::new(2);
-LL | |         yield;
-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: generator is not `Sync` as this value is used across a yield
-  --> $DIR/not-send-sync.rs:12:9
-   |
-LL |         let a = Cell::new(2);
-   |             - has type `Cell<i32>` which is not `Sync`
-LL |         yield;
-   |         ^^^^^ yield occurs here, with `a` maybe used later
-LL |     });
-   |     - `a` is later dropped here
-note: required by a bound in `assert_sync`
-  --> $DIR/not-send-sync.rs:6:23
-   |
-LL |     fn assert_sync<T: Sync>(_: T) {}
-   |                       ^^^^ required by this bound in `assert_sync`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/generator/parent-expression.drop_tracking.stderr b/tests/ui/generator/parent-expression.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..ef48908
--- /dev/null
@@ -0,0 +1,128 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `derived_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `derived_drop::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `significant_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `significant_drop::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `insignificant_dtor::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/generator/parent-expression.drop_tracking_mir.stderr b/tests/ui/generator/parent-expression.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..bf81445
--- /dev/null
@@ -0,0 +1,122 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:27:13
+   |
+LL |               assert_send(g);
+   |               ^^^^^^^^^^^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `derived_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `derived_drop::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:27:13
+   |
+LL |               assert_send(g);
+   |               ^^^^^^^^^^^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `significant_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `significant_drop::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:27:13
+   |
+LL |               assert_send(g);
+   |               ^^^^^^^^^^^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `insignificant_dtor::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/generator/parent-expression.no_drop_tracking.stderr b/tests/ui/generator/parent-expression.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..2e1313a
--- /dev/null
@@ -0,0 +1,334 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `copy::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `copy::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:40:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `copy::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:38:22
+   |
+LL |               let g = move || match drop($name::Client::default()) {
+   |                                          ------------------------ has type `copy::Client` which is not `Send`
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `derived_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `derived_drop::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:40:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `derived_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:38:22
+   |
+LL |               let g = move || match drop($name::Client::default()) {
+   |                                          ------------------------ has type `derived_drop::Client` which is not `Send`
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `significant_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `significant_drop::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:40:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `significant_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:38:22
+   |
+LL |               let g = move || match drop($name::Client::default()) {
+   |                                          ------------------------ has type `significant_drop::Client` which is not `Send`
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:27:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:25:22
+   |
+LL |               let g = move || match drop($name::Client { ..$name::Client::default() }) {
+   |                                                            ------------------------ has type `insignificant_dtor::Client` which is not `Send`
+...
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+  --> $DIR/parent-expression.rs:40:25
+   |
+LL |               assert_send(g);
+   |                           ^ generator is not `Send`
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+   |
+   = help: within `[generator@$DIR/parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/parent-expression.rs:38:22
+   |
+LL |               let g = move || match drop($name::Client::default()) {
+   |                                          ------------------------ has type `insignificant_dtor::Client` which is not `Send`
+LL |                   _ => yield,
+   |                        ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL |               };
+   |               - `$name::Client::default()` is later dropped here
+...
+LL | /     type_combinations!(
+LL | |         // OK
+LL | |         copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | |         // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+...  |
+LL | |         };
+LL | |     );
+   | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+  --> $DIR/parent-expression.rs:49:19
+   |
+LL | fn assert_send<T: Send>(_thing: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+   = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/generator/parent-expression.rs b/tests/ui/generator/parent-expression.rs
new file mode 100644 (file)
index 0000000..239034e
--- /dev/null
@@ -0,0 +1,77 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+
+#![feature(generators, negative_impls, rustc_attrs)]
+
+macro_rules! type_combinations {
+    (
+        $( $name:ident => { $( $tt:tt )* } );* $(;)?
+    ) => { $(
+        mod $name {
+            $( $tt )*
+
+            impl !Sync for Client {}
+            impl !Send for Client {}
+        }
+
+        // Struct update syntax. This fails because the Client used in the update is considered
+        // dropped *after* the yield.
+        {
+            let g = move || match drop($name::Client { ..$name::Client::default() }) {
+            //~^ `significant_drop::Client` which is not `Send`
+            //~| `insignificant_dtor::Client` which is not `Send`
+            //~| `derived_drop::Client` which is not `Send`
+                _ => yield,
+            };
+            assert_send(g);
+            //~^ ERROR cannot be sent between threads
+            //~| ERROR cannot be sent between threads
+            //~| ERROR cannot be sent between threads
+            //[no_drop_tracking]~^^^^ ERROR cannot be sent between threads
+        }
+
+        // Simple owned value. This works because the Client is considered moved into `drop`,
+        // even though the temporary expression doesn't end until after the yield.
+        {
+            let g = move || match drop($name::Client::default()) {
+                _ => yield,
+            };
+            assert_send(g);
+            //[no_drop_tracking]~^ ERROR cannot be sent between threads
+            //[no_drop_tracking]~| ERROR cannot be sent between threads
+            //[no_drop_tracking]~| ERROR cannot be sent between threads
+            //[no_drop_tracking]~| ERROR cannot be sent between threads
+        }
+    )* }
+}
+
+fn assert_send<T: Send>(_thing: T) {}
+
+fn main() {
+    type_combinations!(
+        // OK
+        copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+        // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+        // this has no `Drop` impl and only the drops of the fields are observable.
+        // FIXME: this should compile.
+        derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+        // NOT OK
+        significant_drop => {
+            #[derive(Default)]
+            pub struct Client;
+            impl Drop for Client {
+                fn drop(&mut self) {}
+            }
+        };
+        // NOT OK (we need to agree with MIR borrowck)
+        insignificant_dtor => {
+            #[derive(Default)]
+            #[rustc_insignificant_dtor]
+            pub struct Client;
+            impl Drop for Client {
+                fn drop(&mut self) {}
+            }
+        };
+    );
+}
diff --git a/tests/ui/generator/partial-drop.drop_tracking.stderr b/tests/ui/generator/partial-drop.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..f1b25cb
--- /dev/null
@@ -0,0 +1,61 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/partial-drop.rs:17:17
+   |
+LL |       assert_send(|| {
+   |  _________________^
+LL | |
+LL | |         let guard = Bar { foo: Foo, x: 42 };
+LL | |         drop(guard.foo);
+LL | |         yield;
+LL | |     });
+   | |_____^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/partial-drop.rs:17:17: 17:19]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/partial-drop.rs:21:9
+   |
+LL |         let guard = Bar { foo: Foo, x: 42 };
+   |             ----- has type `Bar` which is not `Send`
+LL |         drop(guard.foo);
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `guard` maybe used later
+LL |     });
+   |     - `guard` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/partial-drop.rs:33:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/partial-drop.rs:24:17
+   |
+LL |       assert_send(|| {
+   |  _________________^
+LL | |
+LL | |         let guard = Bar { foo: Foo, x: 42 };
+LL | |         let Bar { foo, x } = guard;
+LL | |         drop(foo);
+LL | |         yield;
+LL | |     });
+   | |_____^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/partial-drop.rs:24:17: 24:19]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/partial-drop.rs:29:9
+   |
+LL |         let guard = Bar { foo: Foo, x: 42 };
+   |             ----- has type `Bar` which is not `Send`
+...
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `guard` maybe used later
+LL |     });
+   |     - `guard` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/partial-drop.rs:33:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/generator/partial-drop.no_drop_tracking.stderr b/tests/ui/generator/partial-drop.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..91152b5
--- /dev/null
@@ -0,0 +1,61 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/partial-drop.rs:17:17
+   |
+LL |       assert_send(|| {
+   |  _________________^
+LL | |
+LL | |         let guard = Bar { foo: Foo, x: 42 };
+LL | |         drop(guard.foo);
+LL | |         yield;
+LL | |     });
+   | |_____^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/partial-drop.rs:17:17: 17:19]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/partial-drop.rs:21:9
+   |
+LL |         let guard = Bar { foo: Foo, x: 42 };
+   |             ----- has type `Bar` which is not `Send`
+LL |         drop(guard.foo);
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `guard` maybe used later
+LL |     });
+   |     - `guard` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/partial-drop.rs:33:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/partial-drop.rs:24:17
+   |
+LL |       assert_send(|| {
+   |  _________________^
+LL | |
+LL | |         let guard = Bar { foo: Foo, x: 42 };
+LL | |         let Bar { foo, x } = guard;
+LL | |         drop(foo);
+LL | |         yield;
+LL | |     });
+   | |_____^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/partial-drop.rs:24:17: 24:19]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/partial-drop.rs:29:9
+   |
+LL |         let Bar { foo, x } = guard;
+   |                   --- has type `Foo` which is not `Send`
+LL |         drop(foo);
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `foo` maybe used later
+LL |     });
+   |     - `foo` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/partial-drop.rs:33:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 2 previous errors
+
index c872fb7f3e6305745d3d4ff91c3d6a32aebdf3f7..1d3ae075d43afb448beb8ea97070d1e8a818d164 100644 (file)
@@ -1,4 +1,7 @@
-// compile-flags: -Zdrop-tracking
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+// [drop_tracking_mir] check-pass
 
 #![feature(negative_impls, generators)]
 
@@ -12,26 +15,14 @@ struct Bar {
 
 fn main() {
     assert_send(|| {
-        //~^ ERROR generator cannot be sent between threads safely
-        // FIXME: it would be nice to make this work.
+        //[no_drop_tracking,drop_tracking]~^ ERROR generator cannot be sent between threads safely
         let guard = Bar { foo: Foo, x: 42 };
         drop(guard.foo);
         yield;
     });
 
     assert_send(|| {
-        //~^ ERROR generator cannot be sent between threads safely
-        // FIXME: it would be nice to make this work.
-        let guard = Bar { foo: Foo, x: 42 };
-        drop(guard);
-        guard.foo = Foo;
-        guard.x = 23;
-        yield;
-    });
-
-    assert_send(|| {
-        //~^ ERROR generator cannot be sent between threads safely
-        // FIXME: it would be nice to make this work.
+        //[no_drop_tracking,drop_tracking]~^ ERROR generator cannot be sent between threads safely
         let guard = Bar { foo: Foo, x: 42 };
         let Bar { foo, x } = guard;
         drop(foo);
diff --git a/tests/ui/generator/partial-drop.stderr b/tests/ui/generator/partial-drop.stderr
deleted file mode 100644 (file)
index 9baafe5..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-error: generator cannot be sent between threads safely
-  --> $DIR/partial-drop.rs:14:17
-   |
-LL |       assert_send(|| {
-   |  _________________^
-LL | |
-LL | |         // FIXME: it would be nice to make this work.
-LL | |         let guard = Bar { foo: Foo, x: 42 };
-LL | |         drop(guard.foo);
-LL | |         yield;
-LL | |     });
-   | |_____^ generator is not `Send`
-   |
-   = help: within `[generator@$DIR/partial-drop.rs:14:17: 14:19]`, the trait `Send` is not implemented for `Foo`
-note: generator is not `Send` as this value is used across a yield
-  --> $DIR/partial-drop.rs:19:9
-   |
-LL |         let guard = Bar { foo: Foo, x: 42 };
-   |             ----- has type `Bar` which is not `Send`
-LL |         drop(guard.foo);
-LL |         yield;
-   |         ^^^^^ yield occurs here, with `guard` maybe used later
-LL |     });
-   |     - `guard` is later dropped here
-note: required by a bound in `assert_send`
-  --> $DIR/partial-drop.rs:42:19
-   |
-LL | fn assert_send<T: Send>(_: T) {}
-   |                   ^^^^ required by this bound in `assert_send`
-
-error: generator cannot be sent between threads safely
-  --> $DIR/partial-drop.rs:22:17
-   |
-LL |       assert_send(|| {
-   |  _________________^
-LL | |
-LL | |         // FIXME: it would be nice to make this work.
-LL | |         let guard = Bar { foo: Foo, x: 42 };
-...  |
-LL | |         yield;
-LL | |     });
-   | |_____^ generator is not `Send`
-   |
-   = help: within `[generator@$DIR/partial-drop.rs:22:17: 22:19]`, the trait `Send` is not implemented for `Foo`
-note: generator is not `Send` as this value is used across a yield
-  --> $DIR/partial-drop.rs:29:9
-   |
-LL |         let guard = Bar { foo: Foo, x: 42 };
-   |             ----- has type `Bar` which is not `Send`
-...
-LL |         yield;
-   |         ^^^^^ yield occurs here, with `guard` maybe used later
-LL |     });
-   |     - `guard` is later dropped here
-note: required by a bound in `assert_send`
-  --> $DIR/partial-drop.rs:42:19
-   |
-LL | fn assert_send<T: Send>(_: T) {}
-   |                   ^^^^ required by this bound in `assert_send`
-
-error: generator cannot be sent between threads safely
-  --> $DIR/partial-drop.rs:32:17
-   |
-LL |       assert_send(|| {
-   |  _________________^
-LL | |
-LL | |         // FIXME: it would be nice to make this work.
-LL | |         let guard = Bar { foo: Foo, x: 42 };
-...  |
-LL | |         yield;
-LL | |     });
-   | |_____^ generator is not `Send`
-   |
-   = help: within `[generator@$DIR/partial-drop.rs:32:17: 32:19]`, the trait `Send` is not implemented for `Foo`
-note: generator is not `Send` as this value is used across a yield
-  --> $DIR/partial-drop.rs:38:9
-   |
-LL |         let guard = Bar { foo: Foo, x: 42 };
-   |             ----- has type `Bar` which is not `Send`
-...
-LL |         yield;
-   |         ^^^^^ yield occurs here, with `guard` maybe used later
-LL |     });
-   |     - `guard` is later dropped here
-note: required by a bound in `assert_send`
-  --> $DIR/partial-drop.rs:42:19
-   |
-LL | fn assert_send<T: Send>(_: T) {}
-   |                   ^^^^ required by this bound in `assert_send`
-
-error: aborting due to 3 previous errors
-
diff --git a/tests/ui/generator/print/generator-print-verbose-1.drop_tracking.stderr b/tests/ui/generator/print/generator-print-verbose-1.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..7d0a201
--- /dev/null
@@ -0,0 +1,64 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/generator-print-verbose-1.rs:40:18
+   |
+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:38:9
+   |
+LL |         let _non_send_gen = make_non_send_generator();
+   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
+LL |     };
+   |     - `_non_send_gen` is later dropped here
+note: required by a bound in `require_send`
+  --> $DIR/generator-print-verbose-1.rs:29:25
+   |
+LL | fn require_send(_: impl Send) {}
+   |                         ^^^^ required by this bound in `require_send`
+
+error[E0277]: `RefCell<i32>` cannot be shared between threads safely
+  --> $DIR/generator-print-verbose-1.rs:59:18
+   |
+LL |     require_send(send_gen);
+   |     ------------ ^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
+   |     |
+   |     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:45:5
+   |
+LL |     || {
+   |     ^^
+note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])`
+  --> $DIR/generator-print-verbose-1.rs:44:30
+   |
+LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`
+  --> $DIR/generator-print-verbose-1.rs:50:34
+   |
+LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> {
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`, `()`
+note: required because it's used within this generator
+  --> $DIR/generator-print-verbose-1.rs:55:20
+   |
+LL |     let send_gen = || {
+   |                    ^^
+note: required by a bound in `require_send`
+  --> $DIR/generator-print-verbose-1.rs:29:25
+   |
+LL | fn require_send(_: impl Send) {}
+   |                         ^^^^ required by this bound in `require_send`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/generator/print/generator-print-verbose-1.drop_tracking_mir.stderr b/tests/ui/generator/print/generator-print-verbose-1.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..c045b14
--- /dev/null
@@ -0,0 +1,60 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/generator-print-verbose-1.rs:40:5
+   |
+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:38:9
+   |
+LL |         let _non_send_gen = make_non_send_generator();
+   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
+note: required by a bound in `require_send`
+  --> $DIR/generator-print-verbose-1.rs:29:25
+   |
+LL | fn require_send(_: impl Send) {}
+   |                         ^^^^ required by this bound in `require_send`
+
+error[E0277]: `RefCell<i32>` cannot be shared between threads safely
+  --> $DIR/generator-print-verbose-1.rs:59:5
+   |
+LL |     require_send(send_gen);
+   |     ^^^^^^^^^^^^ `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 for `Arc<RefCell<i32>>` to implement `Send`
+note: required because it's used within this generator
+  --> $DIR/generator-print-verbose-1.rs:45:5
+   |
+LL |     || {
+   |     ^^
+note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])`
+  --> $DIR/generator-print-verbose-1.rs:44:30
+   |
+LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`
+  --> $DIR/generator-print-verbose-1.rs:50:34
+   |
+LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> {
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`
+note: required because it's used within this generator
+  --> $DIR/generator-print-verbose-1.rs:55:20
+   |
+LL |     let send_gen = || {
+   |                    ^^
+note: required by a bound in `require_send`
+  --> $DIR/generator-print-verbose-1.rs:29:25
+   |
+LL | fn require_send(_: impl Send) {}
+   |                         ^^^^ required by this bound in `require_send`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/generator/print/generator-print-verbose-1.no_drop_tracking.stderr b/tests/ui/generator/print/generator-print-verbose-1.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..7d0a201
--- /dev/null
@@ -0,0 +1,64 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/generator-print-verbose-1.rs:40:18
+   |
+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:38:9
+   |
+LL |         let _non_send_gen = make_non_send_generator();
+   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
+LL |     };
+   |     - `_non_send_gen` is later dropped here
+note: required by a bound in `require_send`
+  --> $DIR/generator-print-verbose-1.rs:29:25
+   |
+LL | fn require_send(_: impl Send) {}
+   |                         ^^^^ required by this bound in `require_send`
+
+error[E0277]: `RefCell<i32>` cannot be shared between threads safely
+  --> $DIR/generator-print-verbose-1.rs:59:18
+   |
+LL |     require_send(send_gen);
+   |     ------------ ^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
+   |     |
+   |     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:45:5
+   |
+LL |     || {
+   |     ^^
+note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])`
+  --> $DIR/generator-print-verbose-1.rs:44:30
+   |
+LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`
+  --> $DIR/generator-print-verbose-1.rs:50:34
+   |
+LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> {
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`, `()`
+note: required because it's used within this generator
+  --> $DIR/generator-print-verbose-1.rs:55:20
+   |
+LL |     let send_gen = || {
+   |                    ^^
+note: required by a bound in `require_send`
+  --> $DIR/generator-print-verbose-1.rs:29:25
+   |
+LL | fn require_send(_: impl Send) {}
+   |                         ^^^^ required by this bound in `require_send`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 89124ad7289acdc64764e7be72380bfdb0840cc8..c7052c7d1b04d5fa9ce393a2f1e3c60e17a6c28f 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // compile-flags: -Zverbose
 
 // Same as: tests/ui/generator/issue-68112.stderr
@@ -12,7 +15,7 @@
 };
 
 pub struct Ready<T>(Option<T>);
-impl<T> Generator<()> for Ready<T> {
+impl<T: Unpin> Generator<()> for Ready<T> {
     type Return = T;
     type Yield = ();
     fn resume(mut self: Pin<&mut Self>, _args: ()) -> GeneratorState<(), T> {
diff --git a/tests/ui/generator/print/generator-print-verbose-1.stderr b/tests/ui/generator/print/generator-print-verbose-1.stderr
deleted file mode 100644 (file)
index ebf35be..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-error: generator cannot be sent between threads safely
-  --> $DIR/generator-print-verbose-1.rs:37:18
-   |
-LL |     require_send(send_gen);
-   |                  ^^^^^^^^ generator is not `Send`
-   |
-   = help: the trait `Sync` is not implemented for `RefCell<i32>`
-note: generator is not `Send` as this value is used across a yield
-  --> $DIR/generator-print-verbose-1.rs:35:9
-   |
-LL |         let _non_send_gen = make_non_send_generator();
-   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
-LL |         yield;
-   |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
-LL |     };
-   |     - `_non_send_gen` is later dropped here
-note: required by a bound in `require_send`
-  --> $DIR/generator-print-verbose-1.rs:26:25
-   |
-LL | fn require_send(_: impl Send) {}
-   |                         ^^^^ required by this bound in `require_send`
-
-error[E0277]: `RefCell<i32>` cannot be shared between threads safely
-  --> $DIR/generator-print-verbose-1.rs:56:18
-   |
-LL |     require_send(send_gen);
-   |     ------------ ^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
-   |     |
-   |     required by a bound introduced by this call
-   |
-   = help: the trait `Sync` is not implemented for `RefCell<i32>`
-   = 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
-   |
-LL |     || {
-   |     ^^
-note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])`
-  --> $DIR/generator-print-verbose-1.rs:41:30
-   |
-LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`
-  --> $DIR/generator-print-verbose-1.rs:47:34
-   |
-LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> {
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`, `()`
-note: required because it's used within this generator
-  --> $DIR/generator-print-verbose-1.rs:52:20
-   |
-LL |     let send_gen = || {
-   |                    ^^
-note: required by a bound in `require_send`
-  --> $DIR/generator-print-verbose-1.rs:26:25
-   |
-LL | fn require_send(_: impl Send) {}
-   |                         ^^^^ required by this bound in `require_send`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/generator/print/generator-print-verbose-2.drop_tracking.stderr b/tests/ui/generator/print/generator-print-verbose-2.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..1f2e530
--- /dev/null
@@ -0,0 +1,60 @@
+error: generator cannot be shared between threads safely
+  --> $DIR/generator-print-verbose-2.rs:20:17
+   |
+LL |       assert_sync(|| {
+   |  _________________^
+LL | |
+LL | |         let a = NotSync;
+LL | |         yield;
+LL | |         drop(a);
+LL | |     });
+   | |_____^ generator is not `Sync`
+   |
+   = help: within `[main::{closure#0} upvar_tys=() {NotSync, ()}]`, the trait `Sync` is not implemented for `NotSync`
+note: generator is not `Sync` as this value is used across a yield
+  --> $DIR/generator-print-verbose-2.rs:23:9
+   |
+LL |         let a = NotSync;
+   |             - has type `NotSync` which is not `Sync`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+LL |         drop(a);
+LL |     });
+   |     - `a` is later dropped here
+note: required by a bound in `assert_sync`
+  --> $DIR/generator-print-verbose-2.rs:17:23
+   |
+LL |     fn assert_sync<T: Sync>(_: T) {}
+   |                       ^^^^ required by this bound in `assert_sync`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/generator-print-verbose-2.rs:27:17
+   |
+LL |       assert_send(|| {
+   |  _________________^
+LL | |
+LL | |         let a = NotSend;
+LL | |         yield;
+LL | |         drop(a);
+LL | |     });
+   | |_____^ generator is not `Send`
+   |
+   = help: within `[main::{closure#1} upvar_tys=() {NotSend, ()}]`, the trait `Send` is not implemented for `NotSend`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/generator-print-verbose-2.rs:30:9
+   |
+LL |         let a = NotSend;
+   |             - has type `NotSend` which is not `Send`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+LL |         drop(a);
+LL |     });
+   |     - `a` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/generator-print-verbose-2.rs:18:23
+   |
+LL |     fn assert_send<T: Send>(_: T) {}
+   |                       ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/generator/print/generator-print-verbose-2.drop_tracking_mir.stderr b/tests/ui/generator/print/generator-print-verbose-2.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..354369f
--- /dev/null
@@ -0,0 +1,42 @@
+error: generator cannot be shared between threads safely
+  --> $DIR/generator-print-verbose-2.rs:20:5
+   |
+LL |     assert_sync(|| {
+   |     ^^^^^^^^^^^ generator is not `Sync`
+   |
+   = help: within `[main::{closure#0} upvar_tys=() [main::{closure#0}]]`, the trait `Sync` is not implemented for `NotSync`
+note: generator is not `Sync` as this value is used across a yield
+  --> $DIR/generator-print-verbose-2.rs:23:9
+   |
+LL |         let a = NotSync;
+   |             - has type `NotSync` which is not `Sync`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+note: required by a bound in `assert_sync`
+  --> $DIR/generator-print-verbose-2.rs:17:23
+   |
+LL |     fn assert_sync<T: Sync>(_: T) {}
+   |                       ^^^^ required by this bound in `assert_sync`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/generator-print-verbose-2.rs:27:5
+   |
+LL |     assert_send(|| {
+   |     ^^^^^^^^^^^ generator is not `Send`
+   |
+   = help: within `[main::{closure#1} upvar_tys=() [main::{closure#1}]]`, the trait `Send` is not implemented for `NotSend`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/generator-print-verbose-2.rs:30:9
+   |
+LL |         let a = NotSend;
+   |             - has type `NotSend` which is not `Send`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+note: required by a bound in `assert_send`
+  --> $DIR/generator-print-verbose-2.rs:18:23
+   |
+LL |     fn assert_send<T: Send>(_: T) {}
+   |                       ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/generator/print/generator-print-verbose-2.no_drop_tracking.stderr b/tests/ui/generator/print/generator-print-verbose-2.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..1f2e530
--- /dev/null
@@ -0,0 +1,60 @@
+error: generator cannot be shared between threads safely
+  --> $DIR/generator-print-verbose-2.rs:20:17
+   |
+LL |       assert_sync(|| {
+   |  _________________^
+LL | |
+LL | |         let a = NotSync;
+LL | |         yield;
+LL | |         drop(a);
+LL | |     });
+   | |_____^ generator is not `Sync`
+   |
+   = help: within `[main::{closure#0} upvar_tys=() {NotSync, ()}]`, the trait `Sync` is not implemented for `NotSync`
+note: generator is not `Sync` as this value is used across a yield
+  --> $DIR/generator-print-verbose-2.rs:23:9
+   |
+LL |         let a = NotSync;
+   |             - has type `NotSync` which is not `Sync`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+LL |         drop(a);
+LL |     });
+   |     - `a` is later dropped here
+note: required by a bound in `assert_sync`
+  --> $DIR/generator-print-verbose-2.rs:17:23
+   |
+LL |     fn assert_sync<T: Sync>(_: T) {}
+   |                       ^^^^ required by this bound in `assert_sync`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/generator-print-verbose-2.rs:27:17
+   |
+LL |       assert_send(|| {
+   |  _________________^
+LL | |
+LL | |         let a = NotSend;
+LL | |         yield;
+LL | |         drop(a);
+LL | |     });
+   | |_____^ generator is not `Send`
+   |
+   = help: within `[main::{closure#1} upvar_tys=() {NotSend, ()}]`, the trait `Send` is not implemented for `NotSend`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/generator-print-verbose-2.rs:30:9
+   |
+LL |         let a = NotSend;
+   |             - has type `NotSend` which is not `Send`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+LL |         drop(a);
+LL |     });
+   |     - `a` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/generator-print-verbose-2.rs:18:23
+   |
+LL |     fn assert_send<T: Send>(_: T) {}
+   |                       ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 2 previous errors
+
index d914719cb36bb7d40b072d14128a473ab130ade6..ab29db6e09c964475a86222f7156dafe2d97c2e8 100644 (file)
@@ -1,9 +1,17 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // compile-flags: -Zverbose
 
 // Same as test/ui/generator/not-send-sync.rs
 #![feature(generators)]
+#![feature(negative_impls)]
 
-use std::cell::Cell;
+struct NotSend;
+struct NotSync;
+
+impl !Send for NotSend {}
+impl !Sync for NotSync {}
 
 fn main() {
     fn assert_sync<T: Sync>(_: T) {}
@@ -11,14 +19,15 @@ fn assert_send<T: Send>(_: T) {}
 
     assert_sync(|| {
         //~^ ERROR: generator cannot be shared between threads safely
-        let a = Cell::new(2);
+        let a = NotSync;
         yield;
+        drop(a);
     });
 
-    let a = Cell::new(2);
     assert_send(|| {
-        //~^ ERROR: E0277
-        drop(&a);
+        //~^ ERROR: generator cannot be sent between threads safely
+        let a = NotSend;
         yield;
+        drop(a);
     });
 }
diff --git a/tests/ui/generator/print/generator-print-verbose-2.stderr b/tests/ui/generator/print/generator-print-verbose-2.stderr
deleted file mode 100644 (file)
index 909e49c..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-error[E0277]: `Cell<i32>` cannot be shared between threads safely
-  --> $DIR/generator-print-verbose-2.rs:19:17
-   |
-LL |       assert_send(|| {
-   |  _____-----------_^
-   | |     |
-   | |     required by a bound introduced by this call
-LL | |
-LL | |         drop(&a);
-LL | |         yield;
-LL | |     });
-   | |_____^ `Cell<i32>` cannot be shared between threads safely
-   |
-   = help: the trait `Sync` is not implemented for `Cell<i32>`
-   = 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
-   |
-LL |     assert_send(|| {
-   |                 ^^
-note: required by a bound in `assert_send`
-  --> $DIR/generator-print-verbose-2.rs:10:23
-   |
-LL |     fn assert_send<T: Send>(_: T) {}
-   |                       ^^^^ required by this bound in `assert_send`
-
-error: generator cannot be shared between threads safely
-  --> $DIR/generator-print-verbose-2.rs:12:17
-   |
-LL |       assert_sync(|| {
-   |  _________________^
-LL | |
-LL | |         let a = Cell::new(2);
-LL | |         yield;
-LL | |     });
-   | |_____^ generator is not `Sync`
-   |
-   = help: within `[main::{closure#0} upvar_tys=() {Cell<i32>, ()}]`, the trait `Sync` is not implemented for `Cell<i32>`
-note: generator is not `Sync` as this value is used across a yield
-  --> $DIR/generator-print-verbose-2.rs:15:9
-   |
-LL |         let a = Cell::new(2);
-   |             - has type `Cell<i32>` which is not `Sync`
-LL |         yield;
-   |         ^^^^^ yield occurs here, with `a` maybe used later
-LL |     });
-   |     - `a` is later dropped here
-note: required by a bound in `assert_sync`
-  --> $DIR/generator-print-verbose-2.rs:9:23
-   |
-LL |     fn assert_sync<T: Sync>(_: T) {}
-   |                       ^^^^ required by this bound in `assert_sync`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/generator/retain-resume-ref.drop_tracking.stderr b/tests/ui/generator/retain-resume-ref.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..7122a95
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0499]: cannot borrow `thing` as mutable more than once at a time
+  --> $DIR/retain-resume-ref.rs:27:25
+   |
+LL |     gen.as_mut().resume(&mut thing);
+   |                         ---------- first mutable borrow occurs here
+LL |     gen.as_mut().resume(&mut thing);
+   |                  ------ ^^^^^^^^^^ second mutable borrow occurs here
+   |                  |
+   |                  first borrow later used by call
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/generator/retain-resume-ref.drop_tracking_mir.stderr b/tests/ui/generator/retain-resume-ref.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..736ed1f
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0499]: cannot borrow `thing` as mutable more than once at a time
+  --> $DIR/retain-resume-ref.rs:27:25
+   |
+LL |     gen.as_mut().resume(&mut thing);
+   |                         ---------- first mutable borrow occurs here
+LL |     gen.as_mut().resume(&mut thing);
+   |                         ^^^^^^^^^^ second mutable borrow occurs here
+LL |
+LL | }
+   | - first borrow might be used here, when `gen` is dropped and runs the destructor for generator
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/generator/retain-resume-ref.no_drop_tracking.stderr b/tests/ui/generator/retain-resume-ref.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..7122a95
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0499]: cannot borrow `thing` as mutable more than once at a time
+  --> $DIR/retain-resume-ref.rs:27:25
+   |
+LL |     gen.as_mut().resume(&mut thing);
+   |                         ---------- first mutable borrow occurs here
+LL |     gen.as_mut().resume(&mut thing);
+   |                  ------ ^^^^^^^^^^ second mutable borrow occurs here
+   |                  |
+   |                  first borrow later used by call
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
index 0606ea71cdf372a84ef2f504543068146144f2a8..0050d98d03ba65943952a8ce3e64df49eddd01f6 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+
 //! This test ensures that a mutable reference cannot be passed as a resume argument twice.
 
 #![feature(generators, generator_trait)]
index e33310d12d9ef762c7bf9ba2f02fe3fa5d371fe0..7122a951e8070221826a23b2c9b59cd34dac0fd8 100644 (file)
@@ -1,5 +1,5 @@
 error[E0499]: cannot borrow `thing` as mutable more than once at a time
-  --> $DIR/retain-resume-ref.rs:23:25
+  --> $DIR/retain-resume-ref.rs:27:25
    |
 LL |     gen.as_mut().resume(&mut thing);
    |                         ---------- first mutable borrow occurs here
index 0fa6d9cdc77b66759276668fff0346df5a803fca..4784ff49be2e97dc210385a4fab50dac1fce4ebc 100644 (file)
@@ -1,6 +1,8 @@
 // build-pass
-// revisions: mir thir
+// revisions: mir thir drop_tracking drop_tracking_mir
 // [thir]compile-flags: -Zthir-unsafeck
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 
 #![feature(generators)]
 
index 719d1bd5a4c7dabf518cdb41e5718b511632d482..5101de19d3cb6ea9ad3df085b6e27b5dc480f84b 100644 (file)
@@ -1,5 +1,5 @@
 // check-fail
-// known-bug
+// known-bug: unknown
 
 // This gives us problems because `for<'a> I::Item<'a>: Debug` should mean "for
 // all 'a where I::Item<'a> is WF", but really means "for all 'a possible"
@@ -29,7 +29,6 @@ fn print_items<I>(_iter: I)
 
 fn main() {
     let slice = &mut ();
-    //~^ temporary value dropped while borrowed
     let windows = WindowsMut { slice };
     print_items::<WindowsMut<'_>>(windows);
 }
index 1c9abc4e837c518aa888649f2b5b57b0265631fa..362aeae23614fcf972a6887d860c037f38064ff8 100644 (file)
@@ -3,7 +3,7 @@ error[E0716]: temporary value dropped while borrowed
    |
 LL |     let slice = &mut ();
    |                      ^^ creates a temporary value which is freed while still in use
-...
+LL |     let windows = WindowsMut { slice };
 LL |     print_items::<WindowsMut<'_>>(windows);
    |     -------------------------------------- argument requires that borrow lasts for `'static`
 LL | }
index 8e6c5348e71cab2194056bdb3d980a0ccc99fb8c..3174227a7a1e199a24fb633f6f14f417169a44c6 100644 (file)
@@ -1,5 +1,5 @@
 // check-fail
-// known-bug
+// known-bug: unknown
 
 // This gives us problems because `for<'a> I::Item<'a>: Debug` should mean "for
 // all 'a where I::Item<'a> is WF", but really means "for all 'a possible"
@@ -16,7 +16,6 @@ fn fails<I: LendingIterator, F>(iter: &mut I, f: F) -> bool
 {
     let mut iter2 = Eat(iter, f);
     let _next = iter2.next();
-    //~^ borrowed data escapes
     true
 }
 impl<I: LendingIterator> LendingIterator for &mut I {
index fc4e47a3ba18881963003ef6274e597ff4b9256f..973c548d785edd8bf867d6f23620a594b79f5114 100644 (file)
@@ -1,5 +1,5 @@
 // check-fail
-// known-bug
+// known-bug: unknown
 // edition: 2021
 
 // We really should accept this, but we need implied bounds between the regions
@@ -13,7 +13,6 @@ pub trait FutureIterator {
 
 fn call<I: FutureIterator>() -> impl Send {
     async { // a generator checked for autotrait impl `Send`
-        //~^ lifetime bound not satisfied
         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
         async {}.await; // a yield point
     }
@@ -21,16 +20,13 @@ fn call<I: FutureIterator>() -> impl Send {
 
 fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
     async { // a generator checked for autotrait impl `Send`
-        //~^ lifetime bound not satisfied
         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
-        //~^ lifetime may not live long enough
         async {}.await; // a yield point
     }
 }
 
 fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
     async { // a generator checked for autotrait impl `Send`
-        //~^ lifetime bound not satisfied
         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
         async {}.await; // a yield point
     }
index 72ae288dcab64c4a41eb1ae30f6e9d08a8507f6c..9db124a81e487185972de56ae66977fe0b203336 100644 (file)
@@ -2,77 +2,73 @@ error: lifetime bound not satisfied
   --> $DIR/issue-100013.rs:15:5
    |
 LL | /     async { // a generator checked for autotrait impl `Send`
-LL | |
 LL | |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
 LL | |         async {}.await; // a yield point
 LL | |     }
    | |_____^
    |
 note: the lifetime defined here...
-  --> $DIR/issue-100013.rs:17:38
+  --> $DIR/issue-100013.rs:16:38
    |
 LL |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
    |                                      ^^
 note: ...must outlive the lifetime defined here
-  --> $DIR/issue-100013.rs:17:34
+  --> $DIR/issue-100013.rs:16:34
    |
 LL |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
    |                                  ^^
    = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
 
 error: lifetime bound not satisfied
-  --> $DIR/issue-100013.rs:23:5
+  --> $DIR/issue-100013.rs:22:5
    |
 LL | /     async { // a generator checked for autotrait impl `Send`
-LL | |
 LL | |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
-LL | |
 LL | |         async {}.await; // a yield point
 LL | |     }
    | |_____^
    |
 note: the lifetime defined here...
-  --> $DIR/issue-100013.rs:22:14
+  --> $DIR/issue-100013.rs:21:14
    |
 LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
    |              ^^
 note: ...must outlive the lifetime defined here
-  --> $DIR/issue-100013.rs:22:10
+  --> $DIR/issue-100013.rs:21:10
    |
 LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
    |          ^^
    = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
 
 error: lifetime may not live long enough
-  --> $DIR/issue-100013.rs:25:17
+  --> $DIR/issue-100013.rs:23:17
    |
 LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
    |          --  -- lifetime `'b` defined here
    |          |
    |          lifetime `'a` defined here
-...
+LL |     async { // a generator checked for autotrait impl `Send`
 LL |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
 
 error: lifetime bound not satisfied
-  --> $DIR/issue-100013.rs:32:5
+  --> $DIR/issue-100013.rs:29:5
    |
 LL | /     async { // a generator checked for autotrait impl `Send`
-LL | |
 LL | |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
 LL | |         async {}.await; // a yield point
 LL | |     }
    | |_____^
    |
 note: the lifetime defined here...
-  --> $DIR/issue-100013.rs:31:18
+  --> $DIR/issue-100013.rs:28:18
    |
 LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
    |                  ^^
 note: ...must outlive the lifetime defined here
-  --> $DIR/issue-100013.rs:31:10
+  --> $DIR/issue-100013.rs:28:10
    |
 LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
    |          ^^
index dec668bec10edd262f6b5133b62c89cbe154d646..8f2cc45509ffcbd4bd1cfd4bf639d34ef33f7ca7 100644 (file)
@@ -1,5 +1,5 @@
 // check-fail
-// known-bug
+// known-bug: unknown
 
 // We almost certainly want this to pass, but
 // it's particularly difficult currently, because we need a way of specifying
@@ -22,7 +22,6 @@ fn fmap<U>(self) {
 
         arg = self;
         ret = <Self::Base as Functor>::fmap(arg);
-        //~^ type annotations needed
     }
 }
 
index 1dbe1e2cb2245ba1bc4a9f6560dc13ad8394371d..a085096e1f8c569d29e8c3a404a18d9c96b8d581 100644 (file)
@@ -9,6 +9,16 @@ LL | |         // probably should work.
 LL | |         let _x = x;
 LL | |     };
    | |_____^
+   |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/collectivity-regression.rs:11:16
+   |
+LL |     for<'a> T: Get<Value<'a> = ()>,
+   |                ^^^^^^^^^^^^^^^^^^^
+help: consider restricting the type parameter to the `'static` lifetime
+   |
+LL |     for<'a> T: Get<Value<'a> = ()> + 'static,
+   |                                    +++++++++
 
 error: aborting due to previous error
 
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 623adb1c2ad1ecb832616ad35bd3a91a19bacfa9..e5638d90ee8e7a90b7ece6292c4b5627bf1d9a7d 100644 (file)
@@ -17,6 +17,7 @@ LL |     type Copy<T>: Copy = Box<T>;
    |                          ^^^^^^ the trait `Clone` is not implemented for `T`
    |
    = note: required for `Box<T>` to implement `Clone`
+   = note: required for `<Self as UnsafeCopy>::Copy<T>` to implement `Copy`
 note: required by a bound in `UnsafeCopy::Copy`
   --> $DIR/issue-74824.rs:6:19
    |
diff --git a/tests/ui/generic-associated-types/issue-88360.fixed b/tests/ui/generic-associated-types/issue-88360.fixed
new file mode 100644 (file)
index 0000000..3dea8bf
--- /dev/null
@@ -0,0 +1,20 @@
+// run-rustfix
+
+trait GatTrait {
+    type Gat<'a> where Self: 'a;
+
+    fn test(&self) -> Self::Gat<'_>;
+}
+
+trait SuperTrait<T>
+where
+    Self: 'static,
+    for<'a> Self: GatTrait<Gat<'a> = &'a T>,
+{
+    fn copy(&self) -> Self::Gat<'_> where T: Copy {
+        self.test()
+        //~^ mismatched types
+    }
+}
+
+fn main() {}
index c02690618d0ee9bf08ac4651394350436f852c54..4d4c7ea318078ff3412312e010bfa0872e0488ca 100644 (file)
@@ -1,3 +1,5 @@
+// run-rustfix
+
 trait GatTrait {
     type Gat<'a> where Self: 'a;
 
index cd3750344dda126094b8cb9f69aac27f10c3bdf4..520aeff1894835c966b31a3fb1ad01c7ac399442 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-88360.rs:13:9
+  --> $DIR/issue-88360.rs:15:9
    |
 LL | trait SuperTrait<T>
    |                  - this type parameter
@@ -7,13 +7,15 @@ LL | trait SuperTrait<T>
 LL |     fn copy(&self) -> Self::Gat<'_> where T: Copy {
    |                       ------------- expected `&T` because of return type
 LL |         *self.test()
-   |         ^^^^^^^^^^^^
-   |         |
-   |         expected `&T`, found type parameter `T`
-   |         help: consider borrowing here: `&*self.test()`
+   |         ^^^^^^^^^^^^ expected `&T`, found type parameter `T`
    |
    = note:   expected reference `&T`
            found type parameter `T`
+help: consider removing deref here
+   |
+LL -         *self.test()
+LL +         self.test()
+   |
 
 error: aborting due to previous error
 
index c913483a8747c15ef849f859570306d64a177578..9f669b9a5214b1694bb3c42331ca48480826526f 100644 (file)
@@ -23,6 +23,13 @@ LL |         A(self.0 + rhs.0)
    |
    = note: expected type parameter `B`
              found associated type `<B as Add>::Output`
+help: the type constructed contains `<B as Add>::Output` due to the type of the argument passed
+  --> $DIR/missing-bounds.rs:11:9
+   |
+LL |         A(self.0 + rhs.0)
+   |         ^^--------------^
+   |           |
+   |           this argument influences the type of `A`
 note: tuple struct defined here
   --> $DIR/missing-bounds.rs:5:8
    |
diff --git a/tests/ui/generics/issue-106694.rs b/tests/ui/generics/issue-106694.rs
new file mode 100644 (file)
index 0000000..c4b02ee
--- /dev/null
@@ -0,0 +1,24 @@
+trait Trait {}
+
+fn foo(_: impl &Trait) {}
+//~^ ERROR expected a trait, found type
+
+fn bar<T: &Trait>(_: T) {}
+//~^ ERROR expected a trait, found type
+
+fn partially_correct_impl(_: impl &*const &Trait + Copy) {}
+//~^ ERROR expected a trait, found type
+
+fn foo_bad(_: impl &BadTrait) {}
+//~^ ERROR expected a trait, found type
+//~^^ ERROR cannot find trait `BadTrait` in this scope
+
+fn bar_bad<T: &BadTrait>(_: T) {}
+//~^ ERROR expected a trait, found type
+//~^^ ERROR cannot find trait `BadTrait` in this scope
+
+fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {}
+//~^ ERROR expected a trait, found type
+//~^^ ERROR cannot find trait `BadTrait` in this scope
+
+fn main() {}
diff --git a/tests/ui/generics/issue-106694.stderr b/tests/ui/generics/issue-106694.stderr
new file mode 100644 (file)
index 0000000..235b898
--- /dev/null
@@ -0,0 +1,93 @@
+error: expected a trait, found type
+  --> $DIR/issue-106694.rs:3:16
+   |
+LL | fn foo(_: impl &Trait) {}
+   |                ^^^^^^
+   |
+help: consider removing the indirection
+   |
+LL - fn foo(_: impl &Trait) {}
+LL + fn foo(_: impl Trait) {}
+   |
+
+error: expected a trait, found type
+  --> $DIR/issue-106694.rs:6:11
+   |
+LL | fn bar<T: &Trait>(_: T) {}
+   |           ^^^^^^
+   |
+help: consider removing the indirection
+   |
+LL - fn bar<T: &Trait>(_: T) {}
+LL + fn bar<T: Trait>(_: T) {}
+   |
+
+error: expected a trait, found type
+  --> $DIR/issue-106694.rs:9:35
+   |
+LL | fn partially_correct_impl(_: impl &*const &Trait + Copy) {}
+   |                                   ^^^^^^^^^^^^^^
+   |
+help: consider removing the indirection
+   |
+LL - fn partially_correct_impl(_: impl &*const &Trait + Copy) {}
+LL + fn partially_correct_impl(_: impl Trait + Copy) {}
+   |
+
+error: expected a trait, found type
+  --> $DIR/issue-106694.rs:12:20
+   |
+LL | fn foo_bad(_: impl &BadTrait) {}
+   |                    ^^^^^^^^^
+   |
+help: consider removing the indirection
+   |
+LL - fn foo_bad(_: impl &BadTrait) {}
+LL + fn foo_bad(_: impl BadTrait) {}
+   |
+
+error: expected a trait, found type
+  --> $DIR/issue-106694.rs:16:15
+   |
+LL | fn bar_bad<T: &BadTrait>(_: T) {}
+   |               ^^^^^^^^^
+   |
+help: consider removing the indirection
+   |
+LL - fn bar_bad<T: &BadTrait>(_: T) {}
+LL + fn bar_bad<T: BadTrait>(_: T) {}
+   |
+
+error: expected a trait, found type
+  --> $DIR/issue-106694.rs:20:39
+   |
+LL | fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {}
+   |                                       ^^^^^^^^^^^^^^^^^
+   |
+help: consider removing the indirection
+   |
+LL - fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {}
+LL + fn partially_correct_impl_bad(_: impl BadTrait + Copy) {}
+   |
+
+error[E0405]: cannot find trait `BadTrait` in this scope
+  --> $DIR/issue-106694.rs:12:21
+   |
+LL | fn foo_bad(_: impl &BadTrait) {}
+   |                     ^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `BadTrait` in this scope
+  --> $DIR/issue-106694.rs:16:16
+   |
+LL | fn bar_bad<T: &BadTrait>(_: T) {}
+   |                ^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `BadTrait` in this scope
+  --> $DIR/issue-106694.rs:20:48
+   |
+LL | fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {}
+   |                                                ^^^^^^^^ not found in this scope
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0405`.
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs
new file mode 100644 (file)
index 0000000..7ba2b6d
--- /dev/null
@@ -0,0 +1,8 @@
+fn main() {
+    let x = 42;
+    match x {
+        0..=73 => {},
+        74..=> {},   //~ ERROR unexpected `=>` after open range
+                     //~^ ERROR expected one of `=>`, `if`, or `|`, found `>`
+    }
+}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr
new file mode 100644 (file)
index 0000000..9ba6d15
--- /dev/null
@@ -0,0 +1,19 @@
+error: unexpected `=>` after open range
+  --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:11
+   |
+LL |         74..=> {},
+   |           ^^^
+   |
+help: add a space between the pattern and `=>`
+   |
+LL |         74.. => {},
+   |             +
+
+error: expected one of `=>`, `if`, or `|`, found `>`
+  --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:14
+   |
+LL |         74..=> {},
+   |              ^ expected one of `=>`, `if`, or `|`
+
+error: aborting due to 2 previous errors
+
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
diff --git a/tests/ui/higher-rank-trait-bounds/issue-42114.rs b/tests/ui/higher-rank-trait-bounds/issue-42114.rs
new file mode 100644 (file)
index 0000000..01515fd
--- /dev/null
@@ -0,0 +1,20 @@
+// check-pass
+
+fn lifetime<'a>()
+where
+    &'a (): 'a,
+{
+    /* do nothing */
+}
+
+fn doesnt_work()
+where
+    for<'a> &'a (): 'a,
+{
+    /* do nothing */
+}
+
+fn main() {
+    lifetime();
+    doesnt_work();
+}
index 1f2a96a4c411a62bb1c016d41bf478da67cdf201..c01901be5fe78d976d102700253637731c744ba0 100644 (file)
@@ -51,7 +51,7 @@ LL | n!(f);
 LL |         n!(f);
    |            ^ not found in this scope
    |
-   = note: consider importing this function:
+   = help: consider importing this function:
            foo::f
    = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -64,7 +64,7 @@ LL | n!(f);
 LL |                 f
    |                 ^ not found in this scope
    |
-   = note: consider importing this function:
+   = help: consider importing this function:
            foo::f
    = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index 02ddc391f6e3c01f1e22a096ad47ae982771dc3d..3f31b041b62038d329f16c08de10ac3cae1d36c0 100644 (file)
@@ -4,7 +4,7 @@ error: cannot find macro `print` in this scope
 LL |         print!();
    |         ^^^^^
    |
-   = note: consider importing this macro:
+   = help: consider importing this macro:
            std::print
 
 error: aborting due to previous error
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 |
diff --git a/tests/ui/impl-trait/issue-55872-2.drop_tracking.stderr b/tests/ui/impl-trait/issue-55872-2.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..477c964
--- /dev/null
@@ -0,0 +1,8 @@
+error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
+  --> $DIR/issue-55872-2.rs:17:9
+   |
+LL |         async {}
+   |         ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/impl-trait/issue-55872-2.drop_tracking_mir.stderr b/tests/ui/impl-trait/issue-55872-2.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..c14bb5c
--- /dev/null
@@ -0,0 +1,14 @@
+error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
+  --> $DIR/issue-55872-2.rs:17:9
+   |
+LL |         async {}
+   |         ^^^^^^^^
+
+error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
+  --> $DIR/issue-55872-2.rs:17:9
+   |
+LL |         async {}
+   |         ^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/impl-trait/issue-55872-2.no_drop_tracking.stderr b/tests/ui/impl-trait/issue-55872-2.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..477c964
--- /dev/null
@@ -0,0 +1,8 @@
+error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
+  --> $DIR/issue-55872-2.rs:17:9
+   |
+LL |         async {}
+   |         ^^^^^^^^
+
+error: aborting due to previous error
+
index 4443d3c4d0df18a82d6a215a1c8c8fd81ac2c0d0..cbc7b5d62e138a48026cb3be6bba832ead2e8088 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2018
 
 #![feature(type_alias_impl_trait)]
@@ -13,6 +16,7 @@ impl<S> Bar for S {
     fn foo<T>() -> Self::E {
         async {}
         //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
+        //[drop_tracking_mir]~^^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
     }
 }
 
index 11b8485c8bbfe225ebee91f190b09676cf2a934d..477c964bd40fd3b6d17757367d59f5a3b9d24711 100644 (file)
@@ -1,5 +1,5 @@
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-55872-2.rs:14:9
+  --> $DIR/issue-55872-2.rs:17:9
    |
 LL |         async {}
    |         ^^^^^^^^
index 16a1262ec27b3173ec017f00380510a30494b3f0..92a3290622ef267794789f6b0dfb0b0704952f5b 100644 (file)
@@ -8,13 +8,13 @@ LL |     Foo(bar())
    |     ---------- returning here with type `Foo<impl Quux>`
 ...
 LL | fn bar() -> impl Quux {
-   |             --------- returning this opaque type `Foo<impl Quux>`
+   |             --------- returning this type `Foo<impl Quux>`
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/infinite-impl-trait-issue-38064.rs:14:13
    |
 LL | fn foo() -> impl Quux {
-   |             --------- returning this opaque type `Bar<impl Quux>`
+   |             --------- returning this type `Bar<impl Quux>`
 ...
 LL | fn bar() -> impl Quux {
    |             ^^^^^^^^^ recursive opaque type
diff --git a/tests/ui/impl-trait/issues/issue-105826.rs b/tests/ui/impl-trait/issues/issue-105826.rs
new file mode 100644 (file)
index 0000000..06dc2d4
--- /dev/null
@@ -0,0 +1,39 @@
+// check-pass
+
+use std::io::Write;
+
+struct A(Vec<u8>);
+
+struct B<'a> {
+    one: &'a mut A,
+    two: &'a mut Vec<u8>,
+    three: Vec<u8>,
+}
+
+impl<'a> B<'a> {
+    fn one(&mut self) -> &mut impl Write {
+        &mut self.one.0
+    }
+    fn two(&mut self) -> &mut impl Write {
+        &mut *self.two
+    }
+    fn three(&mut self) -> &mut impl Write {
+        &mut self.three
+    }
+}
+
+struct C<'a>(B<'a>);
+
+impl<'a> C<'a> {
+    fn one(&mut self) -> &mut impl Write {
+        self.0.one()
+    }
+    fn two(&mut self) -> &mut impl Write {
+        self.0.two()
+    }
+    fn three(&mut self) -> &mut impl Write {
+        self.0.three()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/recursive-generator.rs b/tests/ui/impl-trait/recursive-generator.rs
new file mode 100644 (file)
index 0000000..e876f0f
--- /dev/null
@@ -0,0 +1,23 @@
+#![feature(generators, generator_trait)]
+
+use std::ops::{Generator, GeneratorState};
+
+fn foo() -> impl Generator<Yield = (), Return = ()> {
+    //~^ ERROR cannot resolve opaque type
+    //~| NOTE recursive opaque type
+    //~| NOTE in this expansion of desugaring of
+    || {
+    //~^ NOTE returning here
+        let mut gen = Box::pin(foo());
+        //~^ NOTE generator captures itself here
+        let mut r = gen.as_mut().resume(());
+        while let GeneratorState::Yielded(v) = r {
+            yield v;
+            r = gen.as_mut().resume(());
+        }
+    }
+}
+
+fn main() {
+    foo();
+}
diff --git a/tests/ui/impl-trait/recursive-generator.stderr b/tests/ui/impl-trait/recursive-generator.stderr
new file mode 100644 (file)
index 0000000..e23fd4b
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-generator.rs:5:13
+   |
+LL |   fn foo() -> impl Generator<Yield = (), Return = ()> {
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type
+...
+LL | /     || {
+LL | |
+LL | |         let mut gen = Box::pin(foo());
+   | |             ------- generator captures itself here
+LL | |
+...  |
+LL | |         }
+LL | |     }
+   | |_____- returning here with type `[generator@$DIR/recursive-generator.rs:9:5: 9:7]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..43118ae
--- /dev/null
@@ -0,0 +1,152 @@
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:11:22
+   |
+LL | fn option(i: i32) -> impl Sized {
+   |                      ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     if i < 0 { None } else { Some((option(i - 1), i)) }
+   |                ----          ------------------------ returning here with type `Option<(impl Sized, i32)>`
+   |                |
+   |                returning here with type `Option<(impl Sized, i32)>`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:16:15
+   |
+LL | fn tuple() -> impl Sized {
+   |               ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     (tuple(),)
+   |     ---------- returning here with type `(impl Sized,)`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:21:15
+   |
+LL | fn array() -> impl Sized {
+   |               ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     [array()]
+   |     --------- returning here with type `[impl Sized; 1]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:26:13
+   |
+LL | fn ptr() -> impl Sized {
+   |             ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     &ptr() as *const _
+   |     ------------------ returning here with type `*const impl Sized`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:31:16
+   |
+LL | fn fn_ptr() -> impl Sized {
+   |                ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     fn_ptr as fn() -> _
+   |     ------------------- returning here with type `fn() -> impl Sized`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:36:25
+   |
+LL |   fn closure_capture() -> impl Sized {
+   |                           ^^^^^^^^^^ recursive opaque type
+...
+LL | /     move || {
+LL | |         x;
+   | |         - closure captures itself here
+LL | |     }
+   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:39:5: 39:12]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:44:29
+   |
+LL |   fn closure_ref_capture() -> impl Sized {
+   |                               ^^^^^^^^^^ recursive opaque type
+...
+LL | /     move || {
+LL | |         &x;
+   | |          - closure captures itself here
+LL | |     }
+   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:47:5: 47:12]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:52:21
+   |
+LL | fn closure_sig() -> impl Sized {
+   |                     ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     || closure_sig()
+   |     ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:54:5: 54:7]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:57:23
+   |
+LL | fn generator_sig() -> impl Sized {
+   |                       ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     || generator_sig()
+   |     ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:59:5: 59:7]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:62:27
+   |
+LL |   fn generator_capture() -> impl Sized {
+   |                             ^^^^^^^^^^ recursive opaque type
+...
+LL | /     move || {
+LL | |         yield;
+LL | |         x;
+   | |         - generator captures itself here
+LL | |     }
+   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:65:5: 65:12]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:71:35
+   |
+LL | fn substs_change<T: 'static>() -> impl Sized {
+   |                                   ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     (substs_change::<&T>(),)
+   |     ------------------------ returning here with type `(impl Sized,)`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:76:24
+   |
+LL |   fn generator_hold() -> impl Sized {
+   |                          ^^^^^^^^^^ recursive opaque type
+LL |
+LL | /     move || {
+LL | |         let x = generator_hold();
+   | |             - generator captures itself here
+LL | |         yield;
+LL | |         x;
+LL | |     }
+   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:78:5: 78:12]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:90:26
+   |
+LL | fn mutual_recursion() -> impl Sync {
+   |                          ^^^^^^^^^ recursive opaque type
+LL |
+LL |     mutual_recursion_b()
+   |     -------------------- returning here with type `impl Sized`
+...
+LL | fn mutual_recursion_b() -> impl Sized {
+   |                            ---------- returning this opaque type `impl Sized`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:95:28
+   |
+LL | fn mutual_recursion() -> impl Sync {
+   |                          --------- returning this opaque type `impl Sync`
+...
+LL | fn mutual_recursion_b() -> impl Sized {
+   |                            ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     mutual_recursion()
+   |     ------------------ returning here with type `impl Sync`
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking_mir.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..662c74b
--- /dev/null
@@ -0,0 +1,144 @@
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:11:22
+   |
+LL | fn option(i: i32) -> impl Sized {
+   |                      ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     if i < 0 { None } else { Some((option(i - 1), i)) }
+   |                ----          ------------------------ returning here with type `Option<(impl Sized, i32)>`
+   |                |
+   |                returning here with type `Option<(impl Sized, i32)>`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:16:15
+   |
+LL | fn tuple() -> impl Sized {
+   |               ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     (tuple(),)
+   |     ---------- returning here with type `(impl Sized,)`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:21:15
+   |
+LL | fn array() -> impl Sized {
+   |               ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     [array()]
+   |     --------- returning here with type `[impl Sized; 1]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:26:13
+   |
+LL | fn ptr() -> impl Sized {
+   |             ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     &ptr() as *const _
+   |     ------------------ returning here with type `*const impl Sized`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:31:16
+   |
+LL | fn fn_ptr() -> impl Sized {
+   |                ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     fn_ptr as fn() -> _
+   |     ------------------- returning here with type `fn() -> impl Sized`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:36:25
+   |
+LL |   fn closure_capture() -> impl Sized {
+   |                           ^^^^^^^^^^ recursive opaque type
+...
+LL | /     move || {
+LL | |         x;
+   | |         - closure captures itself here
+LL | |     }
+   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:39:5: 39:12]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:44:29
+   |
+LL |   fn closure_ref_capture() -> impl Sized {
+   |                               ^^^^^^^^^^ recursive opaque type
+...
+LL | /     move || {
+LL | |         &x;
+   | |          - closure captures itself here
+LL | |     }
+   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:47:5: 47:12]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:52:21
+   |
+LL | fn closure_sig() -> impl Sized {
+   |                     ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     || closure_sig()
+   |     ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:54:5: 54:7]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:57:23
+   |
+LL | fn generator_sig() -> impl Sized {
+   |                       ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     || generator_sig()
+   |     ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:59:5: 59:7]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:62:27
+   |
+LL |   fn generator_capture() -> impl Sized {
+   |                             ^^^^^^^^^^ recursive opaque type
+...
+LL | /     move || {
+LL | |         yield;
+LL | |         x;
+   | |         - generator captures itself here
+LL | |     }
+   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:65:5: 65:12]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:71:35
+   |
+LL | fn substs_change<T: 'static>() -> impl Sized {
+   |                                   ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     (substs_change::<&T>(),)
+   |     ------------------------ returning here with type `(impl Sized,)`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:76:24
+   |
+LL | fn generator_hold() -> impl Sized {
+   |                        ^^^^^^^^^^ recursive opaque type
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:90:26
+   |
+LL | fn mutual_recursion() -> impl Sync {
+   |                          ^^^^^^^^^ recursive opaque type
+LL |
+LL |     mutual_recursion_b()
+   |     -------------------- returning here with type `impl Sized`
+...
+LL | fn mutual_recursion_b() -> impl Sized {
+   |                            ---------- returning this opaque type `impl Sized`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:95:28
+   |
+LL | fn mutual_recursion() -> impl Sync {
+   |                          --------- returning this opaque type `impl Sync`
+...
+LL | fn mutual_recursion_b() -> impl Sized {
+   |                            ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     mutual_recursion()
+   |     ------------------ returning here with type `impl Sync`
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.no_drop_tracking.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..43118ae
--- /dev/null
@@ -0,0 +1,152 @@
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:11:22
+   |
+LL | fn option(i: i32) -> impl Sized {
+   |                      ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     if i < 0 { None } else { Some((option(i - 1), i)) }
+   |                ----          ------------------------ returning here with type `Option<(impl Sized, i32)>`
+   |                |
+   |                returning here with type `Option<(impl Sized, i32)>`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:16:15
+   |
+LL | fn tuple() -> impl Sized {
+   |               ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     (tuple(),)
+   |     ---------- returning here with type `(impl Sized,)`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:21:15
+   |
+LL | fn array() -> impl Sized {
+   |               ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     [array()]
+   |     --------- returning here with type `[impl Sized; 1]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:26:13
+   |
+LL | fn ptr() -> impl Sized {
+   |             ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     &ptr() as *const _
+   |     ------------------ returning here with type `*const impl Sized`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:31:16
+   |
+LL | fn fn_ptr() -> impl Sized {
+   |                ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     fn_ptr as fn() -> _
+   |     ------------------- returning here with type `fn() -> impl Sized`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:36:25
+   |
+LL |   fn closure_capture() -> impl Sized {
+   |                           ^^^^^^^^^^ recursive opaque type
+...
+LL | /     move || {
+LL | |         x;
+   | |         - closure captures itself here
+LL | |     }
+   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:39:5: 39:12]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:44:29
+   |
+LL |   fn closure_ref_capture() -> impl Sized {
+   |                               ^^^^^^^^^^ recursive opaque type
+...
+LL | /     move || {
+LL | |         &x;
+   | |          - closure captures itself here
+LL | |     }
+   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:47:5: 47:12]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:52:21
+   |
+LL | fn closure_sig() -> impl Sized {
+   |                     ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     || closure_sig()
+   |     ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:54:5: 54:7]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:57:23
+   |
+LL | fn generator_sig() -> impl Sized {
+   |                       ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     || generator_sig()
+   |     ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:59:5: 59:7]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:62:27
+   |
+LL |   fn generator_capture() -> impl Sized {
+   |                             ^^^^^^^^^^ recursive opaque type
+...
+LL | /     move || {
+LL | |         yield;
+LL | |         x;
+   | |         - generator captures itself here
+LL | |     }
+   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:65:5: 65:12]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:71:35
+   |
+LL | fn substs_change<T: 'static>() -> impl Sized {
+   |                                   ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     (substs_change::<&T>(),)
+   |     ------------------------ returning here with type `(impl Sized,)`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:76:24
+   |
+LL |   fn generator_hold() -> impl Sized {
+   |                          ^^^^^^^^^^ recursive opaque type
+LL |
+LL | /     move || {
+LL | |         let x = generator_hold();
+   | |             - generator captures itself here
+LL | |         yield;
+LL | |         x;
+LL | |     }
+   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:78:5: 78:12]`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:90:26
+   |
+LL | fn mutual_recursion() -> impl Sync {
+   |                          ^^^^^^^^^ recursive opaque type
+LL |
+LL |     mutual_recursion_b()
+   |     -------------------- returning here with type `impl Sized`
+...
+LL | fn mutual_recursion_b() -> impl Sized {
+   |                            ---------- returning this opaque type `impl Sized`
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:95:28
+   |
+LL | fn mutual_recursion() -> impl Sync {
+   |                          --------- returning this opaque type `impl Sync`
+...
+LL | fn mutual_recursion_b() -> impl Sized {
+   |                            ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     mutual_recursion()
+   |     ------------------ returning here with type `impl Sync`
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0720`.
index ffc0cd9d10c34fc9e4bbbf05b38769b5f1b95e5b..630372e13ed58b8d1c2c216708d3e8bbf6915a03 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+
 // Test that impl trait does not allow creating recursive types that are
 // otherwise forbidden.
 
diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
deleted file mode 100644 (file)
index 2e34d3d..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:7:22
-   |
-LL | fn option(i: i32) -> impl Sized {
-   |                      ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     if i < 0 { None } else { Some((option(i - 1), i)) }
-   |                ----          ------------------------ returning here with type `Option<(impl Sized, i32)>`
-   |                |
-   |                returning here with type `Option<(impl Sized, i32)>`
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:12:15
-   |
-LL | fn tuple() -> impl Sized {
-   |               ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     (tuple(),)
-   |     ---------- returning here with type `(impl Sized,)`
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:17:15
-   |
-LL | fn array() -> impl Sized {
-   |               ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     [array()]
-   |     --------- returning here with type `[impl Sized; 1]`
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:22:13
-   |
-LL | fn ptr() -> impl Sized {
-   |             ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     &ptr() as *const _
-   |     ------------------ returning here with type `*const impl Sized`
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:27:16
-   |
-LL | fn fn_ptr() -> impl Sized {
-   |                ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     fn_ptr as fn() -> _
-   |     ------------------- returning here with type `fn() -> impl Sized`
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:32:25
-   |
-LL |   fn closure_capture() -> impl Sized {
-   |                           ^^^^^^^^^^ recursive opaque type
-...
-LL | /     move || {
-LL | |         x;
-LL | |     }
-   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 35:12]`
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:40:29
-   |
-LL |   fn closure_ref_capture() -> impl Sized {
-   |                               ^^^^^^^^^^ recursive opaque type
-...
-LL | /     move || {
-LL | |         &x;
-LL | |     }
-   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 43:12]`
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:48:21
-   |
-LL | fn closure_sig() -> impl Sized {
-   |                     ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     || closure_sig()
-   |     ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:7]`
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:53:23
-   |
-LL | fn generator_sig() -> impl Sized {
-   |                       ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     || generator_sig()
-   |     ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:7]`
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:58:27
-   |
-LL |   fn generator_capture() -> impl Sized {
-   |                             ^^^^^^^^^^ recursive opaque type
-...
-LL | /     move || {
-LL | |         yield;
-LL | |         x;
-LL | |     }
-   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 61:12]`
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:67:35
-   |
-LL | fn substs_change<T: 'static>() -> impl Sized {
-   |                                   ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     (substs_change::<&T>(),)
-   |     ------------------------ returning here with type `(impl Sized,)`
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:72:24
-   |
-LL |   fn generator_hold() -> impl Sized {
-   |                          ^^^^^^^^^^ recursive opaque type
-LL |
-LL | /     move || {
-LL | |         let x = generator_hold();
-LL | |         yield;
-LL | |         x;
-LL | |     }
-   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 74:12]`
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:86:26
-   |
-LL | fn mutual_recursion() -> impl Sync {
-   |                          ^^^^^^^^^ recursive opaque type
-LL |
-LL |     mutual_recursion_b()
-   |     -------------------- returning here with type `impl Sized`
-...
-LL | fn mutual_recursion_b() -> impl Sized {
-   |                            ---------- returning this opaque type `impl Sized`
-
-error[E0720]: cannot resolve opaque type
-  --> $DIR/recursive-impl-trait-type-indirect.rs:91:28
-   |
-LL | fn mutual_recursion() -> impl Sync {
-   |                          --------- returning this opaque type `impl Sync`
-...
-LL | fn mutual_recursion_b() -> impl Sized {
-   |                            ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     mutual_recursion()
-   |     ------------------ returning here with type `impl Sync`
-
-error: aborting due to 14 previous errors
-
-For more information about this error, try `rustc --explain E0720`.
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 855b1e637e97f5c892796597fae452c54fadc21d..b6b1bc5fccf022a3bcd278ecdf527dcb2296b5dd 100644 (file)
@@ -4,7 +4,7 @@ error[E0432]: unresolved import `super::super::C::D::AA`
 LL |         use super::{super::C::D::AA, AA as _};
    |                     ^^^^^^^^^^^^^^^ no `AA` in `C::D`
    |
-   = note: consider importing this type alias instead:
+   = help: consider importing this type alias instead:
            crate::A::AA
 
 error[E0432]: unresolved import `crate::C::AA`
@@ -13,7 +13,7 @@ error[E0432]: unresolved import `crate::C::AA`
 LL |     use crate::C::{self, AA};
    |                          ^^ no `AA` in `C`
    |
-   = note: consider importing this type alias instead:
+   = help: consider importing this type alias instead:
            crate::A::AA
 
 error[E0432]: unresolved import `crate::C::BB`
@@ -22,7 +22,7 @@ error[E0432]: unresolved import `crate::C::BB`
 LL |     use crate::{A, C::BB};
    |                    ^^^^^ no `BB` in `C`
    |
-   = note: consider importing this type alias instead:
+   = help: consider importing this type alias instead:
            crate::A::BB
 
 error: aborting due to 3 previous errors
index cace2a7a51c8eca5529630fd7788f7415af90c71..f9c5cf920e1f10fc25abc0ab67d36e12ad35295e 100644 (file)
@@ -7,7 +7,7 @@ LL |     use crate::D::B as _;
 help: consider importing this type alias instead
    |
 LL |     use A::B as _;
-   |         ~~~~~~~~~~
+   |         ~~~~~~~~~
 
 error[E0432]: unresolved import `crate::D::B2`
   --> $DIR/bad-import-with-rename.rs:10:9
@@ -18,7 +18,7 @@ LL |     use crate::D::B2;
 help: consider importing this type alias instead
    |
 LL |     use A::B2;
-   |         ~~~~~~
+   |         ~~~~~
 
 error: aborting due to 2 previous errors
 
index 8868ee3aeaadd05cd85725f245651c60d4e77b65..a6a5b1393daecc8e0c7298541f5c5966bb181db8 100644 (file)
@@ -2,7 +2,7 @@ error: expected one of `::`, `;`, or `as`, found `{`
   --> $DIR/import-prefix-macro-1.rs:11:27
    |
 LL |     ($p: path) => (use $p {S, Z});
-   |                           ^^^^^^ expected one of `::`, `;`, or `as`
+   |                           ^ expected one of `::`, `;`, or `as`
 ...
 LL | import! { a::b::c }
    | ------------------- in this macro invocation
index 059ca96808d9ae507c6076d3d339b41dbb17cf72..3448f3119778a6d4b5592297f1c56d0096d2f949 100644 (file)
@@ -7,13 +7,13 @@ LL |     use empty::issue_56125;
 help: consider importing one of these items instead
    |
 LL |     use crate::m3::last_segment::issue_56125;
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL |     use crate::m3::non_last_segment::non_last_segment::issue_56125;
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL |     use issue_56125::issue_56125;
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~
 LL |     use issue_56125::last_segment::issue_56125;
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      and 1 other candidate
 
 error[E0659]: `issue_56125` is ambiguous
index 3b72d57fee41ef03499bce2a8e0207fce291bb5e..5374ba3dc9e6d07783f9914523118b6ea121de6a 100644 (file)
@@ -7,7 +7,7 @@ LL | use single_err::something;
 help: consider importing this module instead
    |
 LL | use glob_ok::something;
-   |     ~~~~~~~~~~~~~~~~~~~
+   |     ~~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/tests/ui/imports/issue-99695-b.fixed b/tests/ui/imports/issue-99695-b.fixed
new file mode 100644 (file)
index 0000000..0e60c73
--- /dev/null
@@ -0,0 +1,20 @@
+// run-rustfix
+#![allow(unused, nonstandard_style)]
+mod m {
+
+    mod p {
+        #[macro_export]
+        macro_rules! nu {
+            {} => {};
+        }
+
+        pub struct other_item;
+    }
+
+    use ::nu;
+pub use self::p::{other_item as _};
+    //~^ ERROR unresolved import `self::p::nu` [E0432]
+    //~| HELP a macro with this name exists at the root of the crate
+}
+
+fn main() {}
diff --git a/tests/ui/imports/issue-99695-b.rs b/tests/ui/imports/issue-99695-b.rs
new file mode 100644 (file)
index 0000000..031443a
--- /dev/null
@@ -0,0 +1,19 @@
+// run-rustfix
+#![allow(unused, nonstandard_style)]
+mod m {
+
+    mod p {
+        #[macro_export]
+        macro_rules! nu {
+            {} => {};
+        }
+
+        pub struct other_item;
+    }
+
+    pub use self::p::{nu, other_item as _};
+    //~^ ERROR unresolved import `self::p::nu` [E0432]
+    //~| HELP a macro with this name exists at the root of the crate
+}
+
+fn main() {}
diff --git a/tests/ui/imports/issue-99695-b.stderr b/tests/ui/imports/issue-99695-b.stderr
new file mode 100644 (file)
index 0000000..b6f5c72
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0432]: unresolved import `self::p::nu`
+  --> $DIR/issue-99695-b.rs:14:23
+   |
+LL |     pub use self::p::{nu, other_item as _};
+   |                       ^^ no `nu` in `m::p`
+   |
+   = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+   |
+LL ~     use ::nu;
+LL ~ pub use self::p::{other_item as _};
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/imports/issue-99695.fixed b/tests/ui/imports/issue-99695.fixed
new file mode 100644 (file)
index 0000000..6bf228b
--- /dev/null
@@ -0,0 +1,17 @@
+// run-rustfix
+#![allow(unused, nonstandard_style)]
+mod m {
+    #[macro_export]
+    macro_rules! nu {
+        {} => {};
+    }
+
+    pub struct other_item;
+
+    use ::nu;
+pub use self::{other_item as _};
+    //~^ ERROR unresolved import `self::nu` [E0432]
+    //~| HELP a macro with this name exists at the root of the crate
+}
+
+fn main() {}
diff --git a/tests/ui/imports/issue-99695.rs b/tests/ui/imports/issue-99695.rs
new file mode 100644 (file)
index 0000000..f7199f1
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+#![allow(unused, nonstandard_style)]
+mod m {
+    #[macro_export]
+    macro_rules! nu {
+        {} => {};
+    }
+
+    pub struct other_item;
+
+    pub use self::{nu, other_item as _};
+    //~^ ERROR unresolved import `self::nu` [E0432]
+    //~| HELP a macro with this name exists at the root of the crate
+}
+
+fn main() {}
diff --git a/tests/ui/imports/issue-99695.stderr b/tests/ui/imports/issue-99695.stderr
new file mode 100644 (file)
index 0000000..0ef762e
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0432]: unresolved import `self::nu`
+  --> $DIR/issue-99695.rs:11:20
+   |
+LL |     pub use self::{nu, other_item as _};
+   |                    ^^ no `nu` in `m`
+   |
+   = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+   |
+LL ~     use ::nu;
+LL ~ pub use self::{other_item as _};
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.
index 2a56aaa44fef23b3ae435b47451aa9e7986f4769..888c321bc479b8269d1c87b8a22fa8ca7a6be61f 100644 (file)
@@ -1,8 +1,6 @@
 error[E0282]: type annotations needed
   --> $DIR/cannot-infer-partial-try-return.rs:20:9
    |
-LL |         infallible()?;
-   |         ------------- type must be known at this point
 LL |         Ok(())
    |         ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
    |
diff --git a/tests/ui/inference/issue-107090.rs b/tests/ui/inference/issue-107090.rs
new file mode 100644 (file)
index 0000000..9426445
--- /dev/null
@@ -0,0 +1,31 @@
+use std::marker::PhantomData;
+struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
+where
+    Foo<'short, 'out, T>: Convert<'a, 'b>;
+    //~^ ERROR mismatched types
+    //~^^ ERROR mismatched types
+    //~^^^ ERROR use of undeclared lifetime name
+    //~| ERROR use of undeclared lifetime name `'out`
+
+trait Convert<'a, 'b>: Sized {
+    fn cast(&'a self) -> &'b Self;
+}
+impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
+    //~^ ERROR use of undeclared lifetime name
+    //~^^ ERROR use of undeclared lifetime name `'out`
+    //~| ERROR cannot infer an appropriate lifetime for lifetime parameter
+    fn cast(&'long self) -> &'short Foo<'short, 'out, T> {
+        //~^ ERROR use of undeclared lifetime name
+        //~| ERROR cannot infer an appropriate lifetime for lifetime parameter
+        self
+    }
+}
+
+fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T {
+    //~^ ERROR use of undeclared lifetime name
+    //~^^ ERROR incompatible lifetime on type
+    //~| ERROR `x` has lifetime `'in_` but it needs to satisfy a `'static` lifetime requirement
+    sadness.cast()
+}
+
+fn main() {}
diff --git a/tests/ui/inference/issue-107090.stderr b/tests/ui/inference/issue-107090.stderr
new file mode 100644 (file)
index 0000000..33cb390
--- /dev/null
@@ -0,0 +1,173 @@
+error[E0261]: use of undeclared lifetime name `'short`
+  --> $DIR/issue-107090.rs:4:9
+   |
+LL |     Foo<'short, 'out, T>: Convert<'a, 'b>;
+   |         ^^^^^^ undeclared lifetime
+   |
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'short` lifetime
+   |
+LL |     for<'short> Foo<'short, 'out, T>: Convert<'a, 'b>;
+   |     +++++++++++
+help: consider introducing lifetime `'short` here
+   |
+LL | struct Foo<'short, 'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
+   |            +++++++
+
+error[E0261]: use of undeclared lifetime name `'out`
+  --> $DIR/issue-107090.rs:4:17
+   |
+LL |     Foo<'short, 'out, T>: Convert<'a, 'b>;
+   |                 ^^^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'out` lifetime
+   |
+LL |     for<'out> Foo<'short, 'out, T>: Convert<'a, 'b>;
+   |     +++++++++
+help: consider introducing lifetime `'out` here
+   |
+LL | struct Foo<'out, 'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
+   |            +++++
+
+error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/issue-107090.rs:13:47
+   |
+LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
+   |      -                                        ^^ undeclared lifetime
+   |      |
+   |      help: consider introducing lifetime `'b` here: `'b,`
+
+error[E0261]: use of undeclared lifetime name `'out`
+  --> $DIR/issue-107090.rs:13:67
+   |
+LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
+   |      - help: consider introducing lifetime `'out` here: `'out,`   ^^^^ undeclared lifetime
+
+error[E0261]: use of undeclared lifetime name `'out`
+  --> $DIR/issue-107090.rs:17:49
+   |
+LL |     fn cast(&'long self) -> &'short Foo<'short, 'out, T> {
+   |                                                 ^^^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'out` here
+   |
+LL |     fn cast<'out>(&'long self) -> &'short Foo<'short, 'out, T> {
+   |            ++++++
+help: consider introducing lifetime `'out` here
+   |
+LL | impl<'out, 'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
+   |      +++++
+
+error[E0261]: use of undeclared lifetime name `'short`
+  --> $DIR/issue-107090.rs:24:68
+   |
+LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T {
+   |           -                                                        ^^^^^^ undeclared lifetime
+   |           |
+   |           help: consider introducing lifetime `'short` here: `'short,`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-107090.rs:4:27
+   |
+LL |     Foo<'short, 'out, T>: Convert<'a, 'b>;
+   |                           ^^^^^^^^^^^^^^^ lifetime mismatch
+   |
+   = note: expected trait `Convert<'static, 'static>`
+              found trait `Convert<'a, 'b>`
+note: the lifetime `'a` as defined here...
+  --> $DIR/issue-107090.rs:2:12
+   |
+LL | struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
+   |            ^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error[E0308]: mismatched types
+  --> $DIR/issue-107090.rs:4:27
+   |
+LL |     Foo<'short, 'out, T>: Convert<'a, 'b>;
+   |                           ^^^^^^^^^^^^^^^ lifetime mismatch
+   |
+   = note: expected trait `Convert<'static, 'static>`
+              found trait `Convert<'a, 'b>`
+note: the lifetime `'b` as defined here...
+  --> $DIR/issue-107090.rs:2:16
+   |
+LL | struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
+   |                ^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'long` due to conflicting requirements
+  --> $DIR/issue-107090.rs:13:55
+   |
+LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
+   |                                                       ^^^^^^^^^^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'short` as defined here...
+  --> $DIR/issue-107090.rs:13:21
+   |
+LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
+   |                     ^^^^^^
+   = note: ...but the lifetime must also be valid for the static lifetime...
+note: ...so that the types are compatible
+  --> $DIR/issue-107090.rs:13:55
+   |
+LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
+   |                                                       ^^^^^^^^^^^^^^^^^^^^
+   = note: expected `Convert<'short, 'static>`
+              found `Convert<'_, 'static>`
+
+error: incompatible lifetime on type
+  --> $DIR/issue-107090.rs:24:29
+   |
+LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T {
+   |                             ^^^^^^^^^^^^^^^^^^
+   |
+note: because this has an unmet lifetime requirement
+  --> $DIR/issue-107090.rs:4:27
+   |
+LL |     Foo<'short, 'out, T>: Convert<'a, 'b>;
+   |                           ^^^^^^^^^^^^^^^ introduces a `'static` lifetime requirement
+note: the lifetime `'out` as defined here...
+  --> $DIR/issue-107090.rs:24:17
+   |
+LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T {
+   |                 ^^^^
+note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
+  --> $DIR/issue-107090.rs:13:1
+   |
+LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0759]: `x` has lifetime `'in_` but it needs to satisfy a `'static` lifetime requirement
+  --> $DIR/issue-107090.rs:24:29
+   |
+LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T {
+   |                             ^^^^^^^^^^^^^^^^^^
+   |                             |
+   |                             this data with lifetime `'in_`...
+   |                             ...is used and required to live as long as `'static` here
+
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'long` due to conflicting requirements
+  --> $DIR/issue-107090.rs:17:13
+   |
+LL |     fn cast(&'long self) -> &'short Foo<'short, 'out, T> {
+   |             ^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'short` as defined here...
+  --> $DIR/issue-107090.rs:13:21
+   |
+LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
+   |                     ^^^^^^
+   = note: ...but the lifetime must also be valid for the static lifetime...
+note: ...so that the types are compatible
+  --> $DIR/issue-107090.rs:17:13
+   |
+LL |     fn cast(&'long self) -> &'short Foo<'short, 'out, T> {
+   |             ^^^^^^^^^^^
+   = note: expected `Convert<'short, 'static>`
+              found `Convert<'_, 'static>`
+
+error: aborting due to 12 previous errors
+
+Some errors have detailed explanations: E0261, E0308, E0495, E0759.
+For more information about an error, try `rustc --explain E0261`.
index eaaef3463ddc9ee467b24e8c66e08d42db6bec42..c387046e91008f6ad823e9c233f9b2c038068e35 100644 (file)
@@ -6,5 +6,5 @@
 
 fn main() {
     let _ = foo("foo");
-    //~^ ERROR: type annotations needed for `[usize; _]`
+    //~^ ERROR: type annotations needed for `[usize; N]`
 }
index f5c84f960641a077f78d561541315f2c39c7abd1..f2ee8692e38a696d111c52ed9659972a7236d3ce 100644 (file)
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed for `[usize; _]`
+error[E0282]: type annotations needed for `[usize; N]`
   --> $DIR/issue-83606.rs:8:9
    |
 LL |     let _ = foo("foo");
@@ -6,7 +6,7 @@ LL |     let _ = foo("foo");
    |
 help: consider giving this pattern a type, where the the value of const parameter `N` is specified
    |
-LL |     let _: [usize; _] = foo("foo");
+LL |     let _: [usize; N] = foo("foo");
    |          ++++++++++++
 
 error: aborting due to previous error
index 9b822714f828a71a446fb169782482e6a0deb58c..a9cb7e5257c83d1db6c8fa8df7e3a1fed7811586 100644 (file)
@@ -1,8 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/question-mark-type-infer.rs:10:30
+  --> $DIR/question-mark-type-infer.rs:10:21
    |
 LL |     l.iter().map(f).collect()?
-   |                              ^ cannot infer type
+   |                     ^^^^^^^ cannot infer type of the type parameter `B` declared on the associated function `collect`
+   |
+help: consider specifying the generic argument
+   |
+LL |     l.iter().map(f).collect::<Vec<_>>()?
+   |                            ++++++++++
 
 error: aborting due to previous error
 
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 6dc8f7ddbc9724991d817fb0d27f7e7e2d10d588..029855de2dea0e594b4d4b64019fc358c967f95d 100644 (file)
@@ -1,4 +1,3 @@
-// run-pass
 // run-rustfix
 
 #![allow(non_snake_case)]
@@ -16,11 +15,11 @@ impl Foo {
         match self {
             &
 Foo::Bar if true
-//~^ WARN pattern binding `Bar` is named the same as one of the variants of the type `Foo`
+//~^ ERROR pattern binding `Bar` is named the same as one of the variants of the type `Foo`
 => println!("bar"),
             &
 Foo::Baz if false
-//~^ WARN pattern binding `Baz` is named the same as one of the variants of the type `Foo`
+//~^ ERROR pattern binding `Baz` is named the same as one of the variants of the type `Foo`
 => println!("baz"),
 _ => ()
         }
index cfdc7c9e754888708a1f3d23efb414a901386fa9..bd9e4ea5b601b0c1f894dca181225a43d76ad40c 100644 (file)
@@ -1,4 +1,3 @@
-// run-pass
 // run-rustfix
 
 #![allow(non_snake_case)]
@@ -16,11 +15,11 @@ fn foo(&self) {
         match self {
             &
 Bar if true
-//~^ WARN pattern binding `Bar` is named the same as one of the variants of the type `Foo`
+//~^ ERROR pattern binding `Bar` is named the same as one of the variants of the type `Foo`
 => println!("bar"),
             &
 Baz if false
-//~^ WARN pattern binding `Baz` is named the same as one of the variants of the type `Foo`
+//~^ ERROR pattern binding `Baz` is named the same as one of the variants of the type `Foo`
 => println!("baz"),
 _ => ()
         }
index 293430691ddcf5a7128a38c55d1c3a12364d5c27..ebbf083b7dea8d1e1fa76ab98303a7fe2d22f02e 100644 (file)
@@ -1,17 +1,17 @@
-warning[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo`
-  --> $DIR/issue-19100.rs:18:1
+error[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo`
+  --> $DIR/issue-19100.rs:17:1
    |
 LL | Bar if true
    | ^^^ help: to match on the variant, qualify the path: `Foo::Bar`
    |
-   = note: `#[warn(bindings_with_variant_name)]` on by default
+   = note: `#[deny(bindings_with_variant_name)]` on by default
 
-warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
-  --> $DIR/issue-19100.rs:22:1
+error[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
+  --> $DIR/issue-19100.rs:21:1
    |
 LL | Baz if false
    | ^^^ help: to match on the variant, qualify the path: `Foo::Baz`
 
-warning: 2 warnings emitted
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0170`.
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
 ...
diff --git a/tests/ui/issues/issue-65634-raw-ident-suggestion.edition2015.stderr b/tests/ui/issues/issue-65634-raw-ident-suggestion.edition2015.stderr
new file mode 100644 (file)
index 0000000..d0cb169
--- /dev/null
@@ -0,0 +1,28 @@
+error[E0034]: multiple applicable items in scope
+  --> $DIR/issue-65634-raw-ident-suggestion.rs:24:13
+   |
+LL |     r#fn {}.r#struct();
+   |             ^^^^^^^^ multiple `r#struct` found
+   |
+note: candidate #1 is defined in an impl of the trait `async` for the type `r#fn`
+  --> $DIR/issue-65634-raw-ident-suggestion.rs:7:5
+   |
+LL |     fn r#struct(&self) {
+   |     ^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl of the trait `await` for the type `r#fn`
+  --> $DIR/issue-65634-raw-ident-suggestion.rs:13:5
+   |
+LL |     fn r#struct(&self) {
+   |     ^^^^^^^^^^^^^^^^^^
+help: disambiguate the associated function for candidate #1
+   |
+LL |     async::r#struct(&r#fn {});
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
+help: disambiguate the associated function for candidate #2
+   |
+LL |     await::r#struct(&r#fn {});
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0034`.
diff --git a/tests/ui/issues/issue-65634-raw-ident-suggestion.edition2018.stderr b/tests/ui/issues/issue-65634-raw-ident-suggestion.edition2018.stderr
new file mode 100644 (file)
index 0000000..a75c1c4
--- /dev/null
@@ -0,0 +1,28 @@
+error[E0034]: multiple applicable items in scope
+  --> $DIR/issue-65634-raw-ident-suggestion.rs:24:13
+   |
+LL |     r#fn {}.r#struct();
+   |             ^^^^^^^^ multiple `r#struct` found
+   |
+note: candidate #1 is defined in an impl of the trait `r#async` for the type `r#fn`
+  --> $DIR/issue-65634-raw-ident-suggestion.rs:7:5
+   |
+LL |     fn r#struct(&self) {
+   |     ^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl of the trait `r#await` for the type `r#fn`
+  --> $DIR/issue-65634-raw-ident-suggestion.rs:13:5
+   |
+LL |     fn r#struct(&self) {
+   |     ^^^^^^^^^^^^^^^^^^
+help: disambiguate the associated function for candidate #1
+   |
+LL |     r#async::r#struct(&r#fn {});
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: disambiguate the associated function for candidate #2
+   |
+LL |     r#await::r#struct(&r#fn {});
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0034`.
index b928510258b2f4a13fb4601473ff5d2d71e9a362..03dd0340c9d69711f844224ff8ef523d847ef003 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: edition2015 edition2018
+//[edition2018]edition:2018
+
 #![allow(non_camel_case_types)]
 
 trait r#async {
diff --git a/tests/ui/issues/issue-65634-raw-ident-suggestion.stderr b/tests/ui/issues/issue-65634-raw-ident-suggestion.stderr
deleted file mode 100644 (file)
index 68ccf5c..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-error[E0034]: multiple applicable items in scope
-  --> $DIR/issue-65634-raw-ident-suggestion.rs:21:13
-   |
-LL |     r#fn {}.r#struct();
-   |             ^^^^^^^^ multiple `r#struct` found
-   |
-note: candidate #1 is defined in an impl of the trait `async` for the type `fn`
-  --> $DIR/issue-65634-raw-ident-suggestion.rs:4:5
-   |
-LL |     fn r#struct(&self) {
-   |     ^^^^^^^^^^^^^^^^^^
-note: candidate #2 is defined in an impl of the trait `await` for the type `fn`
-  --> $DIR/issue-65634-raw-ident-suggestion.rs:10:5
-   |
-LL |     fn r#struct(&self) {
-   |     ^^^^^^^^^^^^^^^^^^
-help: disambiguate the associated function for candidate #1
-   |
-LL |     async::r#struct(&r#fn {});
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
-help: disambiguate the associated function for candidate #2
-   |
-LL |     await::r#struct(&r#fn {});
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0034`.
index 9d11cf19ea77c41a2f65c2c1f18e5aea41ed7f66..fc343bb54aace29f40aa5fd3cd5e87a2497de3e3 100644 (file)
@@ -1,14 +1,16 @@
-error[E0282]: type annotations needed
-  --> $DIR/issue-69455.rs:29:20
+error[E0284]: type annotations needed
+  --> $DIR/issue-69455.rs:29:41
    |
 LL |     println!("{}", 23u64.test(xs.iter().sum()));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `new_display`
+   |                          ----           ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
+   |                          |
+   |                          type must be known at this point
    |
-   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: cannot satisfy `<u64 as Test<_>>::Output == _`
 help: consider specifying the generic argument
    |
-LL |     println!("{}", 23u64.test(xs.iter().sum())::<T>);
-   |                                               +++++
+LL |     println!("{}", 23u64.test(xs.iter().sum::<S>()));
+   |                                            +++++
 
 error[E0283]: type annotations needed
   --> $DIR/issue-69455.rs:29:41
@@ -33,5 +35,5 @@ LL |     println!("{}", 23u64.test(xs.iter().sum::<S>()));
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0282, E0283.
-For more information about an error, try `rustc --explain E0282`.
+Some errors have detailed explanations: E0283, E0284.
+For more information about an error, try `rustc --explain E0283`.
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
+
diff --git a/tests/ui/lifetimes/issue-105507.fixed b/tests/ui/lifetimes/issue-105507.fixed
new file mode 100644 (file)
index 0000000..277ce8a
--- /dev/null
@@ -0,0 +1,43 @@
+// run-rustfix
+//
+#![allow(warnings)]
+struct Wrapper<'a, T: ?Sized>(&'a T);
+
+trait Project {
+    type Projected<'a> where Self: 'a;
+    fn project(this: Wrapper<'_, Self>) -> Self::Projected<'_>;
+}
+trait MyTrait {}
+trait ProjectedMyTrait {}
+
+impl<T> Project for Option<T> {
+    type Projected<'a> = Option<Wrapper<'a, T>> where T: 'a;
+    fn project(this: Wrapper<'_, Self>) -> Self::Projected<'_> {
+        this.0.as_ref().map(Wrapper)
+    }
+}
+
+impl<T: MyTrait> MyTrait for Option<Wrapper<'_, T>> {}
+
+impl<T: ProjectedMyTrait> MyTrait for Wrapper<'_, T> {}
+
+impl<T> ProjectedMyTrait for T
+    where
+        T: Project,
+        for<'a> T::Projected<'a>: MyTrait,
+        //~^ NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime
+        //~| NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime
+{}
+
+fn require_trait<T: MyTrait>(_: T) {}
+
+fn foo<T : MyTrait + 'static + 'static, U : MyTrait + 'static + 'static>(wrap: Wrapper<'_, Option<T>>, wrap1: Wrapper<'_, Option<U>>) {
+    //~^ HELP consider restricting the type parameter to the `'static` lifetime
+    //~| HELP consider restricting the type parameter to the `'static` lifetime
+    require_trait(wrap);
+    //~^ ERROR `T` does not live long enough
+    require_trait(wrap1);
+    //~^ ERROR `U` does not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/lifetimes/issue-105507.rs b/tests/ui/lifetimes/issue-105507.rs
new file mode 100644 (file)
index 0000000..f46c6b6
--- /dev/null
@@ -0,0 +1,43 @@
+// run-rustfix
+//
+#![allow(warnings)]
+struct Wrapper<'a, T: ?Sized>(&'a T);
+
+trait Project {
+    type Projected<'a> where Self: 'a;
+    fn project(this: Wrapper<'_, Self>) -> Self::Projected<'_>;
+}
+trait MyTrait {}
+trait ProjectedMyTrait {}
+
+impl<T> Project for Option<T> {
+    type Projected<'a> = Option<Wrapper<'a, T>> where T: 'a;
+    fn project(this: Wrapper<'_, Self>) -> Self::Projected<'_> {
+        this.0.as_ref().map(Wrapper)
+    }
+}
+
+impl<T: MyTrait> MyTrait for Option<Wrapper<'_, T>> {}
+
+impl<T: ProjectedMyTrait> MyTrait for Wrapper<'_, T> {}
+
+impl<T> ProjectedMyTrait for T
+    where
+        T: Project,
+        for<'a> T::Projected<'a>: MyTrait,
+        //~^ NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime
+        //~| NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime
+{}
+
+fn require_trait<T: MyTrait>(_: T) {}
+
+fn foo<T : MyTrait, U : MyTrait>(wrap: Wrapper<'_, Option<T>>, wrap1: Wrapper<'_, Option<U>>) {
+    //~^ HELP consider restricting the type parameter to the `'static` lifetime
+    //~| HELP consider restricting the type parameter to the `'static` lifetime
+    require_trait(wrap);
+    //~^ ERROR `T` does not live long enough
+    require_trait(wrap1);
+    //~^ ERROR `U` does not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/lifetimes/issue-105507.stderr b/tests/ui/lifetimes/issue-105507.stderr
new file mode 100644 (file)
index 0000000..44d3a7e
--- /dev/null
@@ -0,0 +1,34 @@
+error: `T` does not live long enough
+  --> $DIR/issue-105507.rs:37:5
+   |
+LL |     require_trait(wrap);
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/issue-105507.rs:27:35
+   |
+LL |         for<'a> T::Projected<'a>: MyTrait,
+   |                                   ^^^^^^^
+help: consider restricting the type parameter to the `'static` lifetime
+   |
+LL | fn foo<T : MyTrait + 'static, U : MyTrait + 'static>(wrap: Wrapper<'_, Option<T>>, wrap1: Wrapper<'_, Option<U>>) {
+   |                    +++++++++              +++++++++
+
+error: `U` does not live long enough
+  --> $DIR/issue-105507.rs:39:5
+   |
+LL |     require_trait(wrap1);
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+  --> $DIR/issue-105507.rs:27:35
+   |
+LL |         for<'a> T::Projected<'a>: MyTrait,
+   |                                   ^^^^^^^
+help: consider restricting the type parameter to the `'static` lifetime
+   |
+LL | fn foo<T : MyTrait + 'static, U : MyTrait + 'static>(wrap: Wrapper<'_, Option<T>>, wrap1: Wrapper<'_, Option<U>>) {
+   |                    +++++++++              +++++++++
+
+error: aborting due to 2 previous errors
+
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 133637f9a058be0ebadf393bc84a213d5b20bec9..0d79fc0c770698246470e96fbf2291491cd712bd 100644 (file)
@@ -1,4 +1,4 @@
-error: values of the type `[usize; 4294967295]` are too big for the current architecture
+error: values of the type `[usize; usize::MAX]` are too big for the current architecture
   --> $DIR/issue-15919-32.rs:9:9
    |
 LL |     let x = [0usize; 0xffff_ffff];
index 193b823035c09951f1dd62db96258251e5c8c5ee..3399d644ede3ae8fe28517d997af8e8368b42b55 100644 (file)
@@ -1,4 +1,4 @@
-error: values of the type `[usize; 18446744073709551615]` are too big for the current architecture
+error: values of the type `[usize; usize::MAX]` are too big for the current architecture
   --> $DIR/issue-15919-64.rs:9:9
    |
 LL |     let x = [0usize; 0xffff_ffff_ffff_ffff];
index 8d4cbe201846170474309da211fa78bddf51ae86..56cf5d831bd7e7491d8b75baacd8c05a3b7a5b1e 100644 (file)
@@ -1,5 +1,5 @@
 // build-fail
-// normalize-stderr-test "\[&usize; \d+\]" -> "[&usize; N]"
+// normalize-stderr-test "\[&usize; \d+\]" -> "[&usize; usize::MAX]"
 // error-pattern: too big for the current architecture
 
 // FIXME https://github.com/rust-lang/rust/issues/59774
index 9a6431d44700492cb0ecdb9b63bb9b7bfc4506c6..684db53a9190988b8ab31b73ef7a893fe67ec5ae 100644 (file)
@@ -1,4 +1,4 @@
-error: values of the type `[&usize; N]` are too big for the current architecture
+error: values of the type `[&usize; usize::MAX]` are too big for the current architecture
 
 error: aborting due to previous error
 
index f455dcb06f79dc97aa9e3072699154a3bb8121e5..99f1fdf755aa27c1406e9f48f2f96c90565e6e5e 100644 (file)
@@ -1,7 +1,7 @@
-error[E0080]: values of the type `[u8; SIZE]` are too big for the current architecture
+error[E0080]: values of the type `[u8; usize::MAX]` are too big for the current architecture
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
-note: inside `std::mem::size_of::<[u8; SIZE]>`
+note: inside `std::mem::size_of::<[u8; usize::MAX]>`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
 note: inside `main`
   --> $DIR/issue-55878.rs:7:26
index f7923bd47439f114235b3f16846ae7a56c24e56b..44b2be269494aa94a952ee24195d28adda0823f0 100644 (file)
@@ -1,4 +1,4 @@
-error: values of the type `[u8; 18446744073709551615]` are too big for the current architecture
+error: values of the type `[u8; usize::MAX]` are too big for the current architecture
   --> $DIR/issue-69485-var-size-diffs-too-large.rs:6:5
    |
 LL |     Bug::V([0; !0]);
index dc11d056154273a79626566e0d6d99f4c5a54b07..d5991bcf5693df726787ee5cb4f2ed4005fd4cf2 100644 (file)
@@ -1,4 +1,4 @@
-error: values of the type `[u8; 18446744073709551615]` are too big for the current architecture
+error: values of the type `[u8; usize::MAX]` are too big for the current architecture
 
 error: aborting due to previous error
 
index c37d4f29d10e36bd144a2d7c962179f01a2d8b8e..5eccb8cd5d8d2cc59ea45992eac2ddd530285a9e 100644 (file)
@@ -11,7 +11,7 @@ enum Stack<T> {
 fn is_empty<T>(s: Stack<T>) -> bool {
     match s {
         Nil => true,
-//~^ WARN pattern binding `Nil` is named the same as one of the variants of the type `Stack`
+//~^ ERROR pattern binding `Nil` is named the same as one of the variants of the type `Stack`
         _ => false
 //~^ ERROR unreachable pattern
     }
index 849ff1ebd9236183243008893688da508441acfa..baf6c0d7a59d84da505cd17ade601b2efb33496e 100644 (file)
@@ -1,10 +1,10 @@
-warning[E0170]: pattern binding `Nil` is named the same as one of the variants of the type `Stack`
+error[E0170]: pattern binding `Nil` is named the same as one of the variants of the type `Stack`
   --> $DIR/issue-30302.rs:13:9
    |
 LL |         Nil => true,
    |         ^^^ help: to match on the variant, qualify the path: `Stack::Nil`
    |
-   = note: `#[warn(bindings_with_variant_name)]` on by default
+   = note: `#[deny(bindings_with_variant_name)]` on by default
 
 error: unreachable pattern
   --> $DIR/issue-30302.rs:15:9
@@ -21,6 +21,6 @@ note: the lint level is defined here
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0170`.
index d4e88aa26436162160ff0ccc02e3b169e9b4de17..59dba536f24b61bf5635cad404d4ba8695bbedbf 100644 (file)
@@ -21,18 +21,18 @@ fn main() {
     match foo::Foo::Foo {
         Foo => {}
     //~^ ERROR variable `Foo` should have a snake case name
-    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
+    //~^^ ERROR `Foo` is named the same as one of the variants of the type `foo::Foo`
     //~^^^ WARN unused variable: `Foo`
     }
 
     let Foo = foo::Foo::Foo;
     //~^ ERROR variable `Foo` should have a snake case name
-    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
+    //~^^ ERROR `Foo` is named the same as one of the variants of the type `foo::Foo`
     //~^^^ WARN unused variable: `Foo`
 
     fn in_param(Foo: foo::Foo) {}
     //~^ ERROR variable `Foo` should have a snake case name
-    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
+    //~^^ ERROR `Foo` is named the same as one of the variants of the type `foo::Foo`
     //~^^^ WARN unused variable: `Foo`
 
     test(1);
index d476d856e24c59b060ccdd85be6ff1c681e4180a..42ec9364bc6e68f973295fb9258b34da958bc89d 100644 (file)
@@ -1,18 +1,18 @@
-warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
+error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:22:9
    |
 LL |         Foo => {}
    |         ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
    |
-   = note: `#[warn(bindings_with_variant_name)]` on by default
+   = note: `#[deny(bindings_with_variant_name)]` on by default
 
-warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
+error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:28:9
    |
 LL |     let Foo = foo::Foo::Foo;
    |         ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
 
-warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
+error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:33:17
    |
 LL |     fn in_param(Foo: foo::Foo) {}
@@ -85,6 +85,6 @@ error: variable `Foo` should have a snake case name
 LL |     fn in_param(Foo: foo::Foo) {}
    |                 ^^^ help: convert the identifier to snake case (notice the capitalization): `foo`
 
-error: aborting due to 6 previous errors; 6 warnings emitted
+error: aborting due to 9 previous errors; 3 warnings emitted
 
 For more information about this error, try `rustc --explain E0170`.
diff --git a/tests/ui/lint/must_not_suspend/dedup.drop_tracking.stderr b/tests/ui/lint/must_not_suspend/dedup.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..262657d
--- /dev/null
@@ -0,0 +1,21 @@
+error: `No` held across a suspend point, but should not be
+  --> $DIR/dedup.rs:19:9
+   |
+LL |     let no = No {};
+   |         ^^
+LL |     wheeee(&no).await;
+   |                ------ the value is held across this suspend point
+   |
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/dedup.rs:19:9
+   |
+LL |     let no = No {};
+   |         ^^
+note: the lint level is defined here
+  --> $DIR/dedup.rs:6:9
+   |
+LL | #![deny(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/must_not_suspend/dedup.drop_tracking_mir.stderr b/tests/ui/lint/must_not_suspend/dedup.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..262657d
--- /dev/null
@@ -0,0 +1,21 @@
+error: `No` held across a suspend point, but should not be
+  --> $DIR/dedup.rs:19:9
+   |
+LL |     let no = No {};
+   |         ^^
+LL |     wheeee(&no).await;
+   |                ------ the value is held across this suspend point
+   |
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/dedup.rs:19:9
+   |
+LL |     let no = No {};
+   |         ^^
+note: the lint level is defined here
+  --> $DIR/dedup.rs:6:9
+   |
+LL | #![deny(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/must_not_suspend/dedup.no_drop_tracking.stderr b/tests/ui/lint/must_not_suspend/dedup.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..7ed43d2
--- /dev/null
@@ -0,0 +1,33 @@
+error: `No` held across a suspend point, but should not be
+  --> $DIR/dedup.rs:19:9
+   |
+LL |     let no = No {};
+   |         ^^
+LL |     wheeee(&no).await;
+   |                ------ the value is held across this suspend point
+   |
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/dedup.rs:19:9
+   |
+LL |     let no = No {};
+   |         ^^
+note: the lint level is defined here
+  --> $DIR/dedup.rs:6:9
+   |
+LL | #![deny(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: `No` held across a suspend point, but should not be
+  --> $DIR/dedup.rs:20:13
+   |
+LL |     wheeee(&no).await;
+   |             ^^ ------ the value is held across this suspend point
+   |
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/dedup.rs:20:13
+   |
+LL |     wheeee(&no).await;
+   |             ^^
+
+error: aborting due to 2 previous errors
+
index 81a08579bb7bcdf24b62cc49d11ab6045da67b47..96bdb7715b18308f452a412f6cbb87decf7eaba1 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2018
 #![feature(must_not_suspend)]
 #![deny(must_not_suspend)]
@@ -13,7 +16,9 @@ async fn wheeee<T>(t: T) {
 }
 
 async fn yes() {
-    wheeee(&No {}).await; //~ ERROR `No` held across
+    let no = No {}; //~ ERROR `No` held across
+    wheeee(&no).await; //[no_drop_tracking]~ ERROR `No` held across
+    drop(no);
 }
 
 fn main() {
index f8978ba57f15bcf5a774fd18e54bc32e9f9bd3e5..18880f5a757e0f3953c93e96c0108e03d3be9f19 100644 (file)
@@ -1,16 +1,16 @@
 error: `No` held across a suspend point, but should not be
-  --> $DIR/dedup.rs:16:13
+  --> $DIR/dedup.rs:19:13
    |
 LL |     wheeee(&No {}).await;
    |             ^^^^^ ------ the value is held across this suspend point
    |
 help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/dedup.rs:16:13
+  --> $DIR/dedup.rs:19:13
    |
 LL |     wheeee(&No {}).await;
    |             ^^^^^
 note: the lint level is defined here
-  --> $DIR/dedup.rs:3:9
+  --> $DIR/dedup.rs:6:9
    |
 LL | #![deny(must_not_suspend)]
    |         ^^^^^^^^^^^^^^^^
index abf76711bf04f2f218b2ba18aa9fbf0a2aee089f..e3628ca5e493498eaea7849b90ec5c0eecf7ec0a 100644 (file)
@@ -1,5 +1,5 @@
 error: reference to `Umm` held across a suspend point, but should not be
-  --> $DIR/ref.rs:21:13
+  --> $DIR/ref.rs:22:13
    |
 LL |         let guard = &mut self.u;
    |             ^^^^^
@@ -8,17 +8,17 @@ LL |         other().await;
    |                ------ the value is held across this suspend point
    |
 note: You gotta use Umm's, ya know?
-  --> $DIR/ref.rs:21:13
+  --> $DIR/ref.rs:22:13
    |
 LL |         let guard = &mut self.u;
    |             ^^^^^
 help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/ref.rs:21:13
+  --> $DIR/ref.rs:22:13
    |
 LL |         let guard = &mut self.u;
    |             ^^^^^
 note: the lint level is defined here
-  --> $DIR/ref.rs:6:9
+  --> $DIR/ref.rs:7:9
    |
 LL | #![deny(must_not_suspend)]
    |         ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/must_not_suspend/ref.drop_tracking_mir.stderr b/tests/ui/lint/must_not_suspend/ref.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..e3628ca
--- /dev/null
@@ -0,0 +1,27 @@
+error: reference to `Umm` held across a suspend point, but should not be
+  --> $DIR/ref.rs:22:13
+   |
+LL |         let guard = &mut self.u;
+   |             ^^^^^
+LL |
+LL |         other().await;
+   |                ------ the value is held across this suspend point
+   |
+note: You gotta use Umm's, ya know?
+  --> $DIR/ref.rs:22:13
+   |
+LL |         let guard = &mut self.u;
+   |             ^^^^^
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/ref.rs:22:13
+   |
+LL |         let guard = &mut self.u;
+   |             ^^^^^
+note: the lint level is defined here
+  --> $DIR/ref.rs:7:9
+   |
+LL | #![deny(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 41ac09ea72aaa4fe055e8ee1800aba11c80b39ac..e9bfa08b5ddd93035c306273a3c94a591cb75075 100644 (file)
@@ -1,5 +1,5 @@
 error: `Umm` held across a suspend point, but should not be
-  --> $DIR/ref.rs:21:26
+  --> $DIR/ref.rs:22:26
    |
 LL |         let guard = &mut self.u;
    |                          ^^^^^^
@@ -8,17 +8,17 @@ LL |         other().await;
    |                ------ the value is held across this suspend point
    |
 note: You gotta use Umm's, ya know?
-  --> $DIR/ref.rs:21:26
+  --> $DIR/ref.rs:22:26
    |
 LL |         let guard = &mut self.u;
    |                          ^^^^^^
 help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/ref.rs:21:26
+  --> $DIR/ref.rs:22:26
    |
 LL |         let guard = &mut self.u;
    |                          ^^^^^^
 note: the lint level is defined here
-  --> $DIR/ref.rs:6:9
+  --> $DIR/ref.rs:7:9
    |
 LL | #![deny(must_not_suspend)]
    |         ^^^^^^^^^^^^^^^^
index f6b23746fef130f7f6c5afe68762ec24de3b4f39..d05dcb83ac57c5f21fad3c245426ce619fb6a33c 100644 (file)
@@ -1,7 +1,8 @@
 // edition:2018
-// revisions: no_drop_tracking drop_tracking
-// [drop_tracking] compile-flags: -Zdrop-tracking=yes
-// [no_drop_tracking] compile-flags: -Zdrop-tracking=no
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
+
 #![feature(must_not_suspend)]
 #![deny(must_not_suspend)]
 
@@ -22,6 +23,7 @@ async fn uhoh(&mut self) {
 
         other().await;
 
+        let _g = &*guard;
         *guard = Umm { i: 2 }
     }
 }
diff --git a/tests/ui/lint/must_not_suspend/trait.drop_tracking.stderr b/tests/ui/lint/must_not_suspend/trait.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..6e62a22
--- /dev/null
@@ -0,0 +1,37 @@
+error: implementer of `Wow` held across a suspend point, but should not be
+  --> $DIR/trait.rs:24:9
+   |
+LL |     let _guard1 = r#impl();
+   |         ^^^^^^^
+...
+LL |     other().await;
+   |            ------ the value is held across this suspend point
+   |
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/trait.rs:24:9
+   |
+LL |     let _guard1 = r#impl();
+   |         ^^^^^^^
+note: the lint level is defined here
+  --> $DIR/trait.rs:6:9
+   |
+LL | #![deny(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: boxed `Wow` trait object held across a suspend point, but should not be
+  --> $DIR/trait.rs:25:9
+   |
+LL |     let _guard2 = r#dyn();
+   |         ^^^^^^^
+LL |
+LL |     other().await;
+   |            ------ the value is held across this suspend point
+   |
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/trait.rs:25:9
+   |
+LL |     let _guard2 = r#dyn();
+   |         ^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/must_not_suspend/trait.drop_tracking_mir.stderr b/tests/ui/lint/must_not_suspend/trait.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..6e62a22
--- /dev/null
@@ -0,0 +1,37 @@
+error: implementer of `Wow` held across a suspend point, but should not be
+  --> $DIR/trait.rs:24:9
+   |
+LL |     let _guard1 = r#impl();
+   |         ^^^^^^^
+...
+LL |     other().await;
+   |            ------ the value is held across this suspend point
+   |
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/trait.rs:24:9
+   |
+LL |     let _guard1 = r#impl();
+   |         ^^^^^^^
+note: the lint level is defined here
+  --> $DIR/trait.rs:6:9
+   |
+LL | #![deny(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: boxed `Wow` trait object held across a suspend point, but should not be
+  --> $DIR/trait.rs:25:9
+   |
+LL |     let _guard2 = r#dyn();
+   |         ^^^^^^^
+LL |
+LL |     other().await;
+   |            ------ the value is held across this suspend point
+   |
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/trait.rs:25:9
+   |
+LL |     let _guard2 = r#dyn();
+   |         ^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/must_not_suspend/trait.no_drop_tracking.stderr b/tests/ui/lint/must_not_suspend/trait.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..6e62a22
--- /dev/null
@@ -0,0 +1,37 @@
+error: implementer of `Wow` held across a suspend point, but should not be
+  --> $DIR/trait.rs:24:9
+   |
+LL |     let _guard1 = r#impl();
+   |         ^^^^^^^
+...
+LL |     other().await;
+   |            ------ the value is held across this suspend point
+   |
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/trait.rs:24:9
+   |
+LL |     let _guard1 = r#impl();
+   |         ^^^^^^^
+note: the lint level is defined here
+  --> $DIR/trait.rs:6:9
+   |
+LL | #![deny(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: boxed `Wow` trait object held across a suspend point, but should not be
+  --> $DIR/trait.rs:25:9
+   |
+LL |     let _guard2 = r#dyn();
+   |         ^^^^^^^
+LL |
+LL |     other().await;
+   |            ------ the value is held across this suspend point
+   |
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/trait.rs:25:9
+   |
+LL |     let _guard2 = r#dyn();
+   |         ^^^^^^^
+
+error: aborting due to 2 previous errors
+
index 6c911cb4b0f09d03cd7cfef2d38558519affb7fd..cc3ae298dbba7ab00f1189de2e42121a6d8e6442 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2018
 #![feature(must_not_suspend)]
 #![deny(must_not_suspend)]
@@ -22,6 +25,9 @@ pub async fn uhoh() {
     let _guard2 = r#dyn(); //~ ERROR boxed `Wow` trait object held across
 
     other().await;
+
+    drop(_guard1);
+    drop(_guard2);
 }
 
 fn main() {
index d64d25aae5274357ef852e2e43ef2dc902db563b..6e62a228a43a5a13a2f379b57c9392dc15060dbd 100644 (file)
@@ -1,5 +1,5 @@
 error: implementer of `Wow` held across a suspend point, but should not be
-  --> $DIR/trait.rs:21:9
+  --> $DIR/trait.rs:24:9
    |
 LL |     let _guard1 = r#impl();
    |         ^^^^^^^
@@ -8,18 +8,18 @@ LL |     other().await;
    |            ------ the value is held across this suspend point
    |
 help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/trait.rs:21:9
+  --> $DIR/trait.rs:24:9
    |
 LL |     let _guard1 = r#impl();
    |         ^^^^^^^
 note: the lint level is defined here
-  --> $DIR/trait.rs:3:9
+  --> $DIR/trait.rs:6:9
    |
 LL | #![deny(must_not_suspend)]
    |         ^^^^^^^^^^^^^^^^
 
 error: boxed `Wow` trait object held across a suspend point, but should not be
-  --> $DIR/trait.rs:22:9
+  --> $DIR/trait.rs:25:9
    |
 LL |     let _guard2 = r#dyn();
    |         ^^^^^^^
@@ -28,7 +28,7 @@ LL |     other().await;
    |            ------ the value is held across this suspend point
    |
 help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/trait.rs:22:9
+  --> $DIR/trait.rs:25:9
    |
 LL |     let _guard2 = r#dyn();
    |         ^^^^^^^
diff --git a/tests/ui/lint/must_not_suspend/unit.drop_tracking.stderr b/tests/ui/lint/must_not_suspend/unit.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..f89b3e3
--- /dev/null
@@ -0,0 +1,26 @@
+error: `Umm` held across a suspend point, but should not be
+  --> $DIR/unit.rs:22:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+LL |     other().await;
+   |            ------ the value is held across this suspend point
+   |
+note: You gotta use Umm's, ya know?
+  --> $DIR/unit.rs:22:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/unit.rs:22:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+note: the lint level is defined here
+  --> $DIR/unit.rs:6:9
+   |
+LL | #![deny(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/must_not_suspend/unit.drop_tracking_mir.stderr b/tests/ui/lint/must_not_suspend/unit.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..f89b3e3
--- /dev/null
@@ -0,0 +1,26 @@
+error: `Umm` held across a suspend point, but should not be
+  --> $DIR/unit.rs:22:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+LL |     other().await;
+   |            ------ the value is held across this suspend point
+   |
+note: You gotta use Umm's, ya know?
+  --> $DIR/unit.rs:22:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/unit.rs:22:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+note: the lint level is defined here
+  --> $DIR/unit.rs:6:9
+   |
+LL | #![deny(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/must_not_suspend/unit.no_drop_tracking.stderr b/tests/ui/lint/must_not_suspend/unit.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..f89b3e3
--- /dev/null
@@ -0,0 +1,26 @@
+error: `Umm` held across a suspend point, but should not be
+  --> $DIR/unit.rs:22:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+LL |     other().await;
+   |            ------ the value is held across this suspend point
+   |
+note: You gotta use Umm's, ya know?
+  --> $DIR/unit.rs:22:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/unit.rs:22:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+note: the lint level is defined here
+  --> $DIR/unit.rs:6:9
+   |
+LL | #![deny(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index d3a19f704324ddefa3d910a5d788d5bbb53233fa..fbc51b366817c9b482a004a108673566729fc30b 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2018
 #![feature(must_not_suspend)]
 #![deny(must_not_suspend)]
@@ -7,7 +10,6 @@ struct Umm {
     i: i64
 }
 
-
 fn bar() -> Umm {
     Umm {
         i: 1
@@ -19,6 +21,7 @@ async fn other() {}
 pub async fn uhoh() {
     let _guard = bar(); //~ ERROR `Umm` held across
     other().await;
+    drop(_guard);
 }
 
 fn main() {
index c967dbac56c2c48ccb9785af905d3d09423a1d07..50ca292c2f6fd625d95880494b4eda552cea0c52 100644 (file)
@@ -1,5 +1,5 @@
 error: `Umm` held across a suspend point, but should not be
-  --> $DIR/unit.rs:20:9
+  --> $DIR/unit.rs:23:9
    |
 LL |     let _guard = bar();
    |         ^^^^^^
@@ -7,17 +7,17 @@ LL |     other().await;
    |            ------ the value is held across this suspend point
    |
 note: You gotta use Umm's, ya know?
-  --> $DIR/unit.rs:20:9
+  --> $DIR/unit.rs:23:9
    |
 LL |     let _guard = bar();
    |         ^^^^^^
 help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/unit.rs:20:9
+  --> $DIR/unit.rs:23:9
    |
 LL |     let _guard = bar();
    |         ^^^^^^
 note: the lint level is defined here
-  --> $DIR/unit.rs:3:9
+  --> $DIR/unit.rs:6:9
    |
 LL | #![deny(must_not_suspend)]
    |         ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/must_not_suspend/warn.drop_tracking.stderr b/tests/ui/lint/must_not_suspend/warn.drop_tracking.stderr
new file mode 100644 (file)
index 0000000..7a42289
--- /dev/null
@@ -0,0 +1,26 @@
+warning: `Umm` held across a suspend point, but should not be
+  --> $DIR/warn.rs:24:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+LL |     other().await;
+   |            ------ the value is held across this suspend point
+   |
+note: You gotta use Umm's, ya know?
+  --> $DIR/warn.rs:24:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/warn.rs:24:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+note: the lint level is defined here
+  --> $DIR/warn.rs:7:9
+   |
+LL | #![warn(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lint/must_not_suspend/warn.drop_tracking_mir.stderr b/tests/ui/lint/must_not_suspend/warn.drop_tracking_mir.stderr
new file mode 100644 (file)
index 0000000..7a42289
--- /dev/null
@@ -0,0 +1,26 @@
+warning: `Umm` held across a suspend point, but should not be
+  --> $DIR/warn.rs:24:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+LL |     other().await;
+   |            ------ the value is held across this suspend point
+   |
+note: You gotta use Umm's, ya know?
+  --> $DIR/warn.rs:24:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/warn.rs:24:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+note: the lint level is defined here
+  --> $DIR/warn.rs:7:9
+   |
+LL | #![warn(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lint/must_not_suspend/warn.no_drop_tracking.stderr b/tests/ui/lint/must_not_suspend/warn.no_drop_tracking.stderr
new file mode 100644 (file)
index 0000000..7a42289
--- /dev/null
@@ -0,0 +1,26 @@
+warning: `Umm` held across a suspend point, but should not be
+  --> $DIR/warn.rs:24:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+LL |     other().await;
+   |            ------ the value is held across this suspend point
+   |
+note: You gotta use Umm's, ya know?
+  --> $DIR/warn.rs:24:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/warn.rs:24:9
+   |
+LL |     let _guard = bar();
+   |         ^^^^^^
+note: the lint level is defined here
+  --> $DIR/warn.rs:7:9
+   |
+LL | #![warn(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
index 7fdea66a23517d5967e4241685820d499471f4e9..5a4863169ea358613ed6a35a83ff535f14d430d5 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: no_drop_tracking drop_tracking drop_tracking_mir
+// [drop_tracking] compile-flags: -Zdrop-tracking
+// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
 // edition:2018
 // run-pass
 #![feature(must_not_suspend)]
@@ -20,6 +23,7 @@ async fn other() {}
 pub async fn uhoh() {
     let _guard = bar(); //~ WARNING `Umm` held across
     other().await;
+    drop(_guard);
 }
 
 fn main() {
index fe551c6521d49a75674e445db8d151118ce1dfbd..7a422891ab1026ce9cc3a2cb4f2944bcae16854c 100644 (file)
@@ -1,5 +1,5 @@
 warning: `Umm` held across a suspend point, but should not be
-  --> $DIR/warn.rs:21:9
+  --> $DIR/warn.rs:24:9
    |
 LL |     let _guard = bar();
    |         ^^^^^^
@@ -7,17 +7,17 @@ LL |     other().await;
    |            ------ the value is held across this suspend point
    |
 note: You gotta use Umm's, ya know?
-  --> $DIR/warn.rs:21:9
+  --> $DIR/warn.rs:24:9
    |
 LL |     let _guard = bar();
    |         ^^^^^^
 help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/warn.rs:21:9
+  --> $DIR/warn.rs:24:9
    |
 LL |     let _guard = bar();
    |         ^^^^^^
 note: the lint level is defined here
-  --> $DIR/warn.rs:4:9
+  --> $DIR/warn.rs:7:9
    |
 LL | #![warn(must_not_suspend)]
    |         ^^^^^^^^^^^^^^^^
index 49608c20524d3a59d73b3463b06b647109b2a143..c60120061643da4f595aef35afbc4279bb0d0693 100644 (file)
@@ -46,3 +46,140 @@ LL |     let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_
 
 warning: 3 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/semicolon-in-expressions-from-macros.rs:9:13
+   |
+LL |         true;
+   |             ^
+...
+LL |         foo!(first)
+   |         ----------- in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+   = note: macro invocations at the end of a block are treated as expressions
+   = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo`
+note: the lint level is defined here
+  --> $DIR/semicolon-in-expressions-from-macros.rs:24:13
+   |
+LL |     #[allow(semicolon_in_expressions_from_macros)]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+Future breakage diagnostic:
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/semicolon-in-expressions-from-macros.rs:9:13
+   |
+LL |         true;
+   |             ^
+...
+LL |     let _ = foo!(second);
+   |             ------------ in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+note: the lint level is defined here
+  --> $DIR/semicolon-in-expressions-from-macros.rs:29:13
+   |
+LL |     #[allow(semicolon_in_expressions_from_macros)]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+Future breakage diagnostic:
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/semicolon-in-expressions-from-macros.rs:9:13
+   |
+LL |         true;
+   |             ^
+...
+LL |         let _ = foo!(third);
+   |                 ----------- in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+note: the lint level is defined here
+  --> $DIR/semicolon-in-expressions-from-macros.rs:32:13
+   |
+LL |     #[allow(semicolon_in_expressions_from_macros)]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+Future breakage diagnostic:
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/semicolon-in-expressions-from-macros.rs:9:13
+   |
+LL |         true;
+   |             ^
+...
+LL |         let _ = foo!(fourth);
+   |                 ------------ in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+note: the lint level is defined here
+  --> $DIR/semicolon-in-expressions-from-macros.rs:37:13
+   |
+LL |     #[allow(semicolon_in_expressions_from_macros)]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+Future breakage diagnostic:
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/semicolon-in-expressions-from-macros.rs:9:13
+   |
+LL |         true;
+   |             ^
+...
+LL |         foo!(warn_in_block)
+   |         ------------------- in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+   = note: macro invocations at the end of a block are treated as expressions
+   = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo`
+note: the lint level is defined here
+  --> $DIR/semicolon-in-expressions-from-macros.rs:4:9
+   |
+LL | #![warn(semicolon_in_expressions_from_macros)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+Future breakage diagnostic:
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/semicolon-in-expressions-from-macros.rs:9:13
+   |
+LL |         true;
+   |             ^
+...
+LL |     let _ = foo!(warn_in_expr);
+   |             ------------------ in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+note: the lint level is defined here
+  --> $DIR/semicolon-in-expressions-from-macros.rs:4:9
+   |
+LL | #![warn(semicolon_in_expressions_from_macros)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+Future breakage diagnostic:
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/semicolon-in-expressions-from-macros.rs:9:13
+   |
+LL |         true;
+   |             ^
+...
+LL |     let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work);
+   |                                                            ------------------------- in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+note: the lint level is defined here
+  --> $DIR/semicolon-in-expressions-from-macros.rs:4:9
+   |
+LL | #![warn(semicolon_in_expressions_from_macros)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
index 16c152eb23c2d7f12a05b99db2d55d09b9ad3e8d..0fec4996f1a0ae16dbce4848a7f7ec446730170f 100644 (file)
@@ -14,3 +14,18 @@ LL |         _ => foo!()
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/warn-semicolon-in-expressions-from-macros.rs:6:13
+   |
+LL |         true;
+   |             ^
+...
+LL |         _ => foo!()
+   |              ------ in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+   = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default
+   = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
diff --git a/tests/ui/lint/unused/issue-105061-array-lint.rs b/tests/ui/lint/unused/issue-105061-array-lint.rs
new file mode 100644 (file)
index 0000000..9b06a4f
--- /dev/null
@@ -0,0 +1,11 @@
+#![warn(unused)]
+#![deny(warnings)]
+
+fn main() {
+    let _x: ([u32; 3]); //~ ERROR unnecessary parentheses around type
+    let _y: [u8; (3)]; //~ ERROR unnecessary parentheses around const expression
+    let _z: ([u8; (3)]);
+    //~^ ERROR unnecessary parentheses around const expression
+    //~| ERROR unnecessary parentheses around type
+
+}
diff --git a/tests/ui/lint/unused/issue-105061-array-lint.stderr b/tests/ui/lint/unused/issue-105061-array-lint.stderr
new file mode 100644 (file)
index 0000000..7eb761a
--- /dev/null
@@ -0,0 +1,56 @@
+error: unnecessary parentheses around type
+  --> $DIR/issue-105061-array-lint.rs:5:13
+   |
+LL |     let _x: ([u32; 3]);
+   |             ^        ^
+   |
+note: the lint level is defined here
+  --> $DIR/issue-105061-array-lint.rs:2:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(unused_parens)]` implied by `#[deny(warnings)]`
+help: remove these parentheses
+   |
+LL -     let _x: ([u32; 3]);
+LL +     let _x: [u32; 3];
+   |
+
+error: unnecessary parentheses around const expression
+  --> $DIR/issue-105061-array-lint.rs:6:18
+   |
+LL |     let _y: [u8; (3)];
+   |                  ^ ^
+   |
+help: remove these parentheses
+   |
+LL -     let _y: [u8; (3)];
+LL +     let _y: [u8; 3];
+   |
+
+error: unnecessary parentheses around type
+  --> $DIR/issue-105061-array-lint.rs:7:13
+   |
+LL |     let _z: ([u8; (3)]);
+   |             ^         ^
+   |
+help: remove these parentheses
+   |
+LL -     let _z: ([u8; (3)]);
+LL +     let _z: [u8; (3)];
+   |
+
+error: unnecessary parentheses around const expression
+  --> $DIR/issue-105061-array-lint.rs:7:19
+   |
+LL |     let _z: ([u8; (3)]);
+   |                   ^ ^
+   |
+help: remove these parentheses
+   |
+LL -     let _z: ([u8; (3)]);
+LL +     let _z: ([u8; 3]);
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/lint/unused/issue-105061-should-lint.rs b/tests/ui/lint/unused/issue-105061-should-lint.rs
new file mode 100644 (file)
index 0000000..7e4e094
--- /dev/null
@@ -0,0 +1,23 @@
+#![warn(unused)]
+#![deny(warnings)]
+
+struct Inv<'a>(&'a mut &'a ());
+
+trait Trait<'a> {}
+impl<'b> Trait<'b> for for<'a> fn(Inv<'a>) {}
+
+fn with_bound()
+where
+    for<'b> (for<'a> fn(Inv<'a>)): Trait<'b>, //~ ERROR unnecessary parentheses around type
+{}
+
+trait Hello<T> {}
+fn with_dyn_bound<T>()
+where
+    (dyn Hello<(for<'b> fn(&'b ()))>): Hello<T> //~ ERROR unnecessary parentheses around type
+{}
+
+fn main() {
+    with_bound();
+    with_dyn_bound();
+}
diff --git a/tests/ui/lint/unused/issue-105061-should-lint.stderr b/tests/ui/lint/unused/issue-105061-should-lint.stderr
new file mode 100644 (file)
index 0000000..e591f1f
--- /dev/null
@@ -0,0 +1,32 @@
+error: unnecessary parentheses around type
+  --> $DIR/issue-105061-should-lint.rs:11:13
+   |
+LL |     for<'b> (for<'a> fn(Inv<'a>)): Trait<'b>,
+   |             ^                   ^
+   |
+note: the lint level is defined here
+  --> $DIR/issue-105061-should-lint.rs:2:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(unused_parens)]` implied by `#[deny(warnings)]`
+help: remove these parentheses
+   |
+LL -     for<'b> (for<'a> fn(Inv<'a>)): Trait<'b>,
+LL +     for<'b> for<'a> fn(Inv<'a>): Trait<'b>,
+   |
+
+error: unnecessary parentheses around type
+  --> $DIR/issue-105061-should-lint.rs:17:16
+   |
+LL |     (dyn Hello<(for<'b> fn(&'b ()))>): Hello<T>
+   |                ^                  ^
+   |
+help: remove these parentheses
+   |
+LL -     (dyn Hello<(for<'b> fn(&'b ()))>): Hello<T>
+LL +     (dyn Hello<for<'b> fn(&'b ())>): Hello<T>
+   |
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/unused/issue-105061.rs b/tests/ui/lint/unused/issue-105061.rs
new file mode 100644 (file)
index 0000000..92d636d
--- /dev/null
@@ -0,0 +1,17 @@
+#![warn(unused)]
+#![deny(warnings)]
+
+struct Inv<'a>(&'a mut &'a ());
+
+trait Trait {}
+impl Trait for (for<'a> fn(Inv<'a>),) {}
+
+
+fn with_bound()
+where
+    ((for<'a> fn(Inv<'a>)),): Trait, //~ ERROR unnecessary parentheses around type
+{}
+
+fn main() {
+    with_bound();
+}
diff --git a/tests/ui/lint/unused/issue-105061.stderr b/tests/ui/lint/unused/issue-105061.stderr
new file mode 100644 (file)
index 0000000..f07aa20
--- /dev/null
@@ -0,0 +1,20 @@
+error: unnecessary parentheses around type
+  --> $DIR/issue-105061.rs:12:6
+   |
+LL |     ((for<'a> fn(Inv<'a>)),): Trait,
+   |      ^                   ^
+   |
+note: the lint level is defined here
+  --> $DIR/issue-105061.rs:2:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(unused_parens)]` implied by `#[deny(warnings)]`
+help: remove these parentheses
+   |
+LL -     ((for<'a> fn(Inv<'a>)),): Trait,
+LL +     (for<'a> fn(Inv<'a>),): Trait,
+   |
+
+error: aborting due to previous error
+
index 1a88d985dd86a6438bf0b6847895a8255c24d5fa..e691fb37e6c43e51341367474a4fe12ac274edd0 100644 (file)
@@ -50,4 +50,8 @@ fn main() {
     if { return } {
 
     }
+
+    // regression test for https://github.com/rust-lang/rust/issues/106899
+    return println!("!");
+    //~^ WARN unnecessary braces
 }
index 5ca4811fc32d8342f523d5af85ea902dcf852510..0d260d2cbc93f5d82dcc96f0c1fee67871bbf273 100644 (file)
@@ -50,4 +50,8 @@ fn main() {
     if { return } {
 
     }
+
+    // regression test for https://github.com/rust-lang/rust/issues/106899
+    return { println!("!") };
+    //~^ WARN unnecessary braces
 }
index 7773f44ea2d38c0860855afe26fd1cc50f0643a8..0b4a1c321805ddea51a8b4261d5794fd89b38efc 100644 (file)
@@ -68,5 +68,17 @@ LL -     consume({ 7 });
 LL +     consume(7);
    |
 
-warning: 5 warnings emitted
+warning: unnecessary braces around `return` value
+  --> $DIR/unused_braces.rs:55:12
+   |
+LL |     return { println!("!") };
+   |            ^^             ^^
+   |
+help: remove these braces
+   |
+LL -     return { println!("!") };
+LL +     return println!("!");
+   |
+
+warning: 6 warnings emitted
 
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 306c08b13573ea5ab1742f69f2e86c49b85d6934..29ccd17e06999abf8a20e0c01dd8eb5775d75e1d 100644 (file)
@@ -18,3 +18,22 @@ LL | #![deny(semicolon_in_expressions_from_macros)]
 
 error: aborting due to previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: trailing semicolon in macro used in expression position
+  --> $DIR/issue-84195-lint-anon-const.rs:8:14
+   |
+LL |     () => { 0; };
+   |              ^
+...
+LL |     let val: [u8; len!()] = [];
+   |                   ------ in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+note: the lint level is defined here
+  --> $DIR/issue-84195-lint-anon-const.rs:5:9
+   |
+LL | #![deny(semicolon_in_expressions_from_macros)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `len` (in Nightly builds, run with -Z macro-backtrace for more info)
+
index cbdef5f0d40a94eb2d4a705ffe70303bda06136a..60ba2eab7a7bfbe8dbfb6f62383a68a2842482da 100644 (file)
@@ -8,7 +8,7 @@ mod hey {
 
 #[derive(Bla)]
 //~^ ERROR cannot find derive macro `Bla`
-//~| NOTE consider importing this derive macro
+//~| HELP consider importing this derive macro
 struct A;
 
 #[derive(println)]
@@ -19,5 +19,5 @@ mod hey {
 fn main() {
     bla!();
     //~^ ERROR cannot find macro `bla`
-    //~| NOTE consider importing this macro
+    //~| HELP consider importing this macro
 }
index 62afa67a783c9404c4288da55d8287035f1ad5b1..fe8a1deaedd77e2f2029b333344f6bc30b258697 100644 (file)
@@ -4,7 +4,7 @@ error: cannot find macro `bla` in this scope
 LL |     bla!();
    |     ^^^
    |
-   = note: consider importing this macro:
+   = help: consider importing this macro:
            crate::hey::bla
 
 error: cannot find derive macro `println` in this scope
@@ -21,7 +21,7 @@ error: cannot find derive macro `Bla` in this scope
 LL | #[derive(Bla)]
    |          ^^^
    |
-   = note: consider importing this derive macro:
+   = help: consider importing this derive macro:
            crate::hey::Bla
 
 error: aborting due to 3 previous errors
index 6ab121f7c06c612605e495221b3f79ebfc6907ac..13cecc3a31d233cb662a6f6a1b62596452fd8a5b 100644 (file)
@@ -16,3 +16,20 @@ LL |     expand_it!()
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/lint-trailing-macro-call.rs:9:25
+   |
+LL |         #[cfg(FALSE)] 25;
+   |                         ^
+...
+LL |     expand_it!()
+   |     ------------ in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+   = note: macro invocations at the end of a block are treated as expressions
+   = note: to ignore the value produced by the macro, add a semicolon after the invocation of `expand_it`
+   = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default
+   = note: this warning originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info)
+
index f597c398b7c17f87d5ba9dcc7cfe1a16abb9dc31..7785f415946277401d7cc61e4d8b0b11af93d987 100644 (file)
@@ -82,3 +82,18 @@ error: aborting due to 6 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0412, E0425.
 For more information about an error, try `rustc --explain E0412`.
+Future incompatibility report: Future breakage diagnostic:
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/macro-context.rs:3:15
+   |
+LL |     () => ( i ; typeof );
+   |               ^
+...
+LL |     let i = m!();
+   |             ---- in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+   = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default
+   = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
index 36aba8aa08a0b18a95c35a0187a8c569e2e55f8c..3f492b141a5f5949875f5c9f33d728ab2c83ddca 100644 (file)
@@ -31,3 +31,20 @@ LL |     foo!()
 
 error: aborting due to previous error; 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/macro-in-expression-context.rs:5:29
+   |
+LL |         assert_eq!("A", "A");
+   |                             ^
+...
+LL |     foo!()
+   |     ------ in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+   = note: macro invocations at the end of a block are treated as expressions
+   = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo`
+   = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default
+   = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
index 326001fc15a9a0b1a6386109bad67daa8a3cc07c..ca5f0f190e8ba445c34214361d8b5d9ab54b762c 100644 (file)
@@ -9,7 +9,7 @@ LL |     macro_two!();
 LL | macro_rules! macro_one { () => ("one") }
    | ---------------------- similarly named macro `macro_one` defined here
    |
-   = note: consider importing this macro:
+   = help: consider importing this macro:
            two_macros::macro_two
 
 error: aborting due to previous error
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
 ...
diff --git a/tests/ui/methods/method-not-found-but-doc-alias.rs b/tests/ui/methods/method-not-found-but-doc-alias.rs
new file mode 100644 (file)
index 0000000..9c6d100
--- /dev/null
@@ -0,0 +1,11 @@
+struct Foo;
+
+impl Foo {
+    #[doc(alias = "quux")]
+    fn bar(&self) {}
+}
+
+fn main() {
+    Foo.quux();
+    //~^ ERROR  no method named `quux` found for struct `Foo` in the current scope
+}
diff --git a/tests/ui/methods/method-not-found-but-doc-alias.stderr b/tests/ui/methods/method-not-found-but-doc-alias.stderr
new file mode 100644 (file)
index 0000000..5102a45
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0599]: no method named `quux` found for struct `Foo` in the current scope
+  --> $DIR/method-not-found-but-doc-alias.rs:9:9
+   |
+LL | struct Foo;
+   | ---------- method `quux` not found for this struct
+...
+LL |     Foo.quux();
+   |         ^^^^ help: there is a method with a similar name: `bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/mir/mir_codegen_ssa.rs b/tests/ui/mir/mir_codegen_ssa.rs
new file mode 100644 (file)
index 0000000..5e2f10c
--- /dev/null
@@ -0,0 +1,19 @@
+// build-pass
+// compile-flags: --crate-type=lib
+#![feature(custom_mir, core_intrinsics)]
+use std::intrinsics::mir::*;
+
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub fn f(a: u32) -> u32 {
+    mir!(
+        let x: u32;
+        {
+            // Previously code generation failed with ICE "use of .. before def ..." because the
+            // definition of x was incorrectly identified as dominating the use of x located in the
+            // same statement:
+            x = x + a;
+            RET = x;
+            Return()
+        }
+    )
+}
index eab8e8e80c424234eea1b862ab531d227cb9cafd..2a36a352c7341644a4c6a653b6b25bcc34e1a476 100644 (file)
@@ -243,10 +243,12 @@ error[E0606]: casting `&{float}` as `f32` is invalid
   --> $DIR/cast-rfc0401.rs:71:30
    |
 LL |     vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>();
-   |                              -^^^^^^^
-   |                              |
-   |                              cannot cast `&{float}` as `f32`
-   |                              help: dereference the expression: `*s`
+   |                              ^^^^^^^^
+   |
+help: dereference the expression
+   |
+LL |     vec![0.0].iter().map(|s| *s as f32).collect::<Vec<f32>>();
+   |                              +
 
 error: aborting due to 34 previous errors
 
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed
new file mode 100644 (file)
index 0000000..6315fcc
--- /dev/null
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+    let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
+    let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
+}
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs
new file mode 100644 (file)
index 0000000..c12c536
--- /dev/null
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+    let _ = (-10..=10).find(|x: i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
+    let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
+}
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr
new file mode 100644 (file)
index 0000000..fb8af4b
--- /dev/null
@@ -0,0 +1,38 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch-issue-45727.rs:3:24
+   |
+LL |     let _ = (-10..=10).find(|x: i32| x.signum() == 0);
+   |                        ^^^^ -------- found signature defined here
+   |                        |
+   |                        expected due to this
+   |
+   = note: expected closure signature `for<'a> fn(&'a {integer}) -> _`
+              found closure signature `fn(i32) -> _`
+note: required by a bound in `find`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider borrowing the argument
+   |
+LL |     let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
+   |                                 +
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch-issue-45727.rs:4:24
+   |
+LL |     let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
+   |                        ^^^^ ----------- found signature defined here
+   |                        |
+   |                        expected due to this
+   |
+   = note: expected closure signature `for<'a> fn(&'a {integer}) -> _`
+              found closure signature `for<'a, 'b, 'c> fn(&'a &'b &'c i32) -> _`
+note: required by a bound in `find`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: do not borrow the argument
+   |
+LL -     let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
+LL +     let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0631`.
index fab9b7edc0cc5a38bb0c6ab566171b51fa5a4b62..811ff0533f0124ff219f580a458a4d1d830af712 100644 (file)
@@ -2,16 +2,18 @@ error[E0631]: type mismatch in closure arguments
   --> $DIR/closure-arg-type-mismatch.rs:3:14
    |
 LL |     a.iter().map(|_: (u32, u32)| 45);
-   |              ^^^ ---------------
-   |              |   |   |
-   |              |   |   help: consider borrowing the argument: `&(u32, u32)`
-   |              |   found signature defined here
+   |              ^^^ --------------- found signature defined here
+   |              |
    |              expected due to this
    |
    = note: expected closure signature `fn(&(u32, u32)) -> _`
               found closure signature `fn((u32, u32)) -> _`
 note: required by a bound in `map`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider borrowing the argument
+   |
+LL |     a.iter().map(|_: &(u32, u32)| 45);
+   |                      +
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/closure-arg-type-mismatch.rs:4:14
index 680aff1726f9f905e056c800fad7a27206bfa5f5..de4e067fead4cce20007ef8415535eb42c1dba5d 100644 (file)
@@ -11,6 +11,13 @@ LL |         Some(true)
    |
    = note: expected type parameter `bool` (type parameter `bool`)
                         found type `bool` (`bool`)
+help: the type constructed contains `bool` due to the type of the argument passed
+  --> $DIR/issue-35030.rs:9:9
+   |
+LL |         Some(true)
+   |         ^^^^^----^
+   |              |
+   |              this argument influences the type of `Some`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
index 72fb0e4d774312780cb81e6e5f8fc1617f0d8113..a6764a1dc6d31675bdc009c343bf93dabda2af0f 100644 (file)
@@ -2,16 +2,18 @@ error[E0631]: type mismatch in closure arguments
   --> $DIR/issue-36053-2.rs:7:32
    |
 LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
-   |                                ^^^^^^ ---------
-   |                                |      |   |
-   |                                |      |   help: consider borrowing the argument: `&&str`
-   |                                |      found signature defined here
+   |                                ^^^^^^ --------- found signature defined here
+   |                                |
    |                                expected due to this
    |
    = note: expected closure signature `for<'a> fn(&'a &str) -> _`
               found closure signature `for<'a> fn(&'a str) -> _`
 note: required by a bound in `filter`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider borrowing the argument
+   |
+LL |     once::<&str>("str").fuse().filter(|a: &&str| true).count();
+   |                                           +
 
 error[E0599]: the method `count` exists for struct `Filter<Fuse<Once<&str>>, [closure@issue-36053-2.rs:7:39]>`, but its trait bounds were not satisfied
   --> $DIR/issue-36053-2.rs:7:55
index a2201b946a6f0d5352c8db71b2e1e8f9972f7b62..05d3de80d8449b4b8e7da07684b29174989854a5 100644 (file)
@@ -6,6 +6,8 @@ LL |     this.is_subset(other)
    |
    = note: the following trait bounds were not satisfied:
            `T: Eq`
+           `T: PartialEq`
+           which is required by `T: Eq`
            `T: Hash`
 help: consider restricting the type parameters to satisfy the trait bounds
    |
index ced062269df68569795cb6fde437c35749c9a5b7..99e291cda0377ccb0e3b05362b0683372529a128 100644 (file)
@@ -4,7 +4,7 @@ error: cannot find macro `macro_two` in this scope
 LL |     macro_two!();
    |     ^^^^^^^^^
    |
-   = note: consider importing this macro:
+   = help: consider importing this macro:
            two_macros::macro_two
 
 error: aborting due to previous error
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;
diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed
new file mode 100644 (file)
index 0000000..0b9a3ba
--- /dev/null
@@ -0,0 +1,11 @@
+// run-rustfix
+use std::pin::Pin;
+
+fn foo(_: &mut ()) {}
+
+fn main() {
+    let mut uwu = ();
+    let mut r = Pin::new(&mut uwu);
+    foo(r.as_mut().get_mut());
+    foo(r.get_mut()); //~ ERROR use of moved value
+}
diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs
new file mode 100644 (file)
index 0000000..0e952b0
--- /dev/null
@@ -0,0 +1,11 @@
+// run-rustfix
+use std::pin::Pin;
+
+fn foo(_: &mut ()) {}
+
+fn main() {
+    let mut uwu = ();
+    let mut r = Pin::new(&mut uwu);
+    foo(r.get_mut());
+    foo(r.get_mut()); //~ ERROR use of moved value
+}
diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr
new file mode 100644 (file)
index 0000000..7e513b7
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0382]: use of moved value: `r`
+  --> $DIR/pin-mut-reborrow-infer-var-issue-107419.rs:10:9
+   |
+LL |     let mut r = Pin::new(&mut uwu);
+   |         ----- move occurs because `r` has type `Pin<&mut ()>`, which does not implement the `Copy` trait
+LL |     foo(r.get_mut());
+   |           --------- `r` moved due to this method call
+LL |     foo(r.get_mut());
+   |         ^ value used here after move
+   |
+note: `Pin::<&'a mut T>::get_mut` takes ownership of the receiver `self`, which moves `r`
+  --> $SRC_DIR/core/src/pin.rs:LL:COL
+help: consider reborrowing the `Pin` instead of moving it
+   |
+LL |     foo(r.as_mut().get_mut());
+   |           +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
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/deli-ident-issue-1.rs b/tests/ui/parser/deli-ident-issue-1.rs
new file mode 100644 (file)
index 0000000..5448526
--- /dev/null
@@ -0,0 +1,24 @@
+#![feature(let_chains)]
+trait Demo {}
+
+impl dyn Demo {
+    pub fn report(&self) -> u32 {
+        let sum = |a: u32,
+                   b: u32,
+                   c: u32| {
+            a + b + c
+        };
+        sum(1, 2, 3)
+    }
+
+    fn check(&self, val: Option<u32>, num: Option<u32>) {
+        if let Some(b) = val
+        && let Some(c) = num {
+        && b == c {
+            //~^ ERROR expected struct
+            //~| ERROR mismatched types
+        }
+    }
+}
+
+fn main() { } //~ ERROR this file contains an unclosed delimiter
diff --git a/tests/ui/parser/deli-ident-issue-1.stderr b/tests/ui/parser/deli-ident-issue-1.stderr
new file mode 100644 (file)
index 0000000..1119edb
--- /dev/null
@@ -0,0 +1,37 @@
+error: this file contains an unclosed delimiter
+  --> $DIR/deli-ident-issue-1.rs:24:66
+   |
+LL | impl dyn Demo {
+   |               - unclosed delimiter
+...
+LL |         && let Some(c) = num {
+   |                              - this delimiter might not be properly closed...
+...
+LL |     }
+   |     - ...as it matches this but it has different indentation
+...
+LL | fn main() { }
+   |                                                                  ^
+
+error[E0574]: expected struct, variant or union type, found local variable `c`
+  --> $DIR/deli-ident-issue-1.rs:17:17
+   |
+LL |         && b == c {
+   |                 ^ not a struct, variant or union type
+
+error[E0308]: mismatched types
+  --> $DIR/deli-ident-issue-1.rs:17:9
+   |
+LL |       fn check(&self, val: Option<u32>, num: Option<u32>) {
+   |                                                           - expected `()` because of default return type
+...
+LL | /         && b == c {
+LL | |
+LL | |
+LL | |         }
+   | |_________^ expected `()`, found `bool`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0574.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/deli-ident-issue-2.rs b/tests/ui/parser/deli-ident-issue-2.rs
new file mode 100644 (file)
index 0000000..5394760
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {
+    if 1 < 2 {
+        let _a = vec!]; //~ ERROR mismatched closing delimiter
+    }
+} //~ ERROR unexpected closing delimiter
+
+fn main() {}
diff --git a/tests/ui/parser/deli-ident-issue-2.stderr b/tests/ui/parser/deli-ident-issue-2.stderr
new file mode 100644 (file)
index 0000000..c8f59c9
--- /dev/null
@@ -0,0 +1,19 @@
+error: unexpected closing delimiter: `}`
+  --> $DIR/deli-ident-issue-2.rs:5:1
+   |
+LL |         let _a = vec!];
+   |                      - missing open `[` for this delimiter
+LL |     }
+LL | }
+   | ^ unexpected closing delimiter
+
+error: mismatched closing delimiter: `]`
+  --> $DIR/deli-ident-issue-2.rs:2:14
+   |
+LL |     if 1 < 2 {
+   |              ^ unclosed delimiter
+LL |         let _a = vec!];
+   |                      ^ mismatched closing delimiter
+
+error: aborting due to 2 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);
+}
diff --git a/tests/ui/parser/issue-68987-unmatch-issue-1.rs b/tests/ui/parser/issue-68987-unmatch-issue-1.rs
new file mode 100644 (file)
index 0000000..30e7ef4
--- /dev/null
@@ -0,0 +1,12 @@
+// This file has unexpected closing delimiter,
+
+fn func(o: Option<u32>) {
+    match o {
+        Some(_x) => {}   // Extra '}'
+            let _ = if true {};
+        }
+        None => {}
+    }
+} //~ ERROR unexpected closing delimiter
+
+fn main() {}
diff --git a/tests/ui/parser/issue-68987-unmatch-issue-1.stderr b/tests/ui/parser/issue-68987-unmatch-issue-1.stderr
new file mode 100644 (file)
index 0000000..2d873b4
--- /dev/null
@@ -0,0 +1,16 @@
+error: unexpected closing delimiter: `}`
+  --> $DIR/issue-68987-unmatch-issue-1.rs:10:1
+   |
+LL |     match o {
+   |             - this delimiter might not be properly closed...
+LL |         Some(_x) => {}   // Extra '}'
+   |                     -- block is empty, you might have not meant to close it
+LL |             let _ = if true {};
+LL |         }
+   |         - ...as it matches this but it has different indentation
+...
+LL | }
+   | ^ unexpected closing delimiter
+
+error: aborting due to previous error
+
diff --git a/tests/ui/parser/issue-68987-unmatch-issue-2.rs b/tests/ui/parser/issue-68987-unmatch-issue-2.rs
new file mode 100644 (file)
index 0000000..89aaa68
--- /dev/null
@@ -0,0 +1,14 @@
+// FIXME: this case need more work to fix
+// currently the TokenTree matching ')' with '{', which is not user friendly for diagnostics
+async fn obstest() -> Result<> {
+    let obs_connect = || -> Result<(), MyError) { //~ ERROR mismatched closing delimiter
+        async {
+        }
+    }
+
+    if let Ok(version, scene_list) = obs_connect() {
+
+    } else {
+
+    }
+} //~ ERROR unexpected closing delimiter
diff --git a/tests/ui/parser/issue-68987-unmatch-issue-2.stderr b/tests/ui/parser/issue-68987-unmatch-issue-2.stderr
new file mode 100644 (file)
index 0000000..2c08d41
--- /dev/null
@@ -0,0 +1,19 @@
+error: unexpected closing delimiter: `}`
+  --> $DIR/issue-68987-unmatch-issue-2.rs:14:1
+   |
+LL |     let obs_connect = || -> Result<(), MyError) {
+   |                                               - missing open `(` for this delimiter
+...
+LL | }
+   | ^ unexpected closing delimiter
+
+error: mismatched closing delimiter: `)`
+  --> $DIR/issue-68987-unmatch-issue-2.rs:3:32
+   |
+LL | async fn obstest() -> Result<> {
+   |                                ^ unclosed delimiter
+LL |     let obs_connect = || -> Result<(), MyError) {
+   |                                               ^ mismatched closing delimiter
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/parser/issue-68987-unmatch-issue-3.rs b/tests/ui/parser/issue-68987-unmatch-issue-3.rs
new file mode 100644 (file)
index 0000000..e98df8d
--- /dev/null
@@ -0,0 +1,8 @@
+// the `{` is closed with `)`, there is a missing `(`
+fn f(i: u32, j: u32) {
+    let res = String::new();
+    let mut cnt = i;
+    while cnt < j {
+        write!&mut res, " "); //~ ERROR mismatched closing delimiter
+    }
+} //~ ERROR unexpected closing delimiter
diff --git a/tests/ui/parser/issue-68987-unmatch-issue-3.stderr b/tests/ui/parser/issue-68987-unmatch-issue-3.stderr
new file mode 100644 (file)
index 0000000..a3fc46a
--- /dev/null
@@ -0,0 +1,19 @@
+error: unexpected closing delimiter: `}`
+  --> $DIR/issue-68987-unmatch-issue-3.rs:8:1
+   |
+LL |         write!&mut res, " ");
+   |                            - missing open `(` for this delimiter
+LL |     }
+LL | }
+   | ^ unexpected closing delimiter
+
+error: mismatched closing delimiter: `)`
+  --> $DIR/issue-68987-unmatch-issue-3.rs:5:19
+   |
+LL |     while cnt < j {
+   |                   ^ unclosed delimiter
+LL |         write!&mut res, " ");
+   |                            ^ mismatched closing delimiter
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/parser/issue-68987-unmatch-issue.rs b/tests/ui/parser/issue-68987-unmatch-issue.rs
new file mode 100644 (file)
index 0000000..5a3620b
--- /dev/null
@@ -0,0 +1,12 @@
+// This file has unexpected closing delimiter,
+
+fn func(o: Option<u32>) {
+    match o {
+        Some(_x) =>   // Missing '{'
+            let _ = if true {};
+        }
+        None => {}
+    }
+} //~ ERROR unexpected closing delimiter
+
+fn main() {}
diff --git a/tests/ui/parser/issue-68987-unmatch-issue.stderr b/tests/ui/parser/issue-68987-unmatch-issue.stderr
new file mode 100644 (file)
index 0000000..cabd133
--- /dev/null
@@ -0,0 +1,16 @@
+error: unexpected closing delimiter: `}`
+  --> $DIR/issue-68987-unmatch-issue.rs:10:1
+   |
+LL |     match o {
+   |             - this delimiter might not be properly closed...
+LL |         Some(_x) =>   // Missing '{'
+LL |             let _ = if true {};
+   |                             -- block is empty, you might have not meant to close it
+LL |         }
+   |         - ...as it matches this but it has different indentation
+...
+LL | }
+   | ^ unexpected closing delimiter
+
+error: aborting due to previous error
+
index 069de33919494658162f84c21cabf37c923f562c..867244b72e8493a0c59974d331c2500ed2e74c17 100644 (file)
@@ -2,8 +2,9 @@ error: this file contains an unclosed delimiter
   --> $DIR/issue-81827.rs:11:27
    |
 LL | fn r()->i{0|{#[cfg(r(0{]0
-   |          -  -             ^
-   |          |  |
+   |          -  -          -  ^
+   |          |  |          |
+   |          |  |          missing open `[` for this delimiter
    |          |  unclosed delimiter
    |          unclosed delimiter
 
@@ -11,8 +12,9 @@ error: this file contains an unclosed delimiter
   --> $DIR/issue-81827.rs:11:27
    |
 LL | fn r()->i{0|{#[cfg(r(0{]0
-   |          -  -             ^
-   |          |  |
+   |          -  -          -  ^
+   |          |  |          |
+   |          |  |          missing open `[` for this delimiter
    |          |  unclosed delimiter
    |          unclosed delimiter
 
index 1f0c1ea4c2f13b032ab6f55c50bf6e2f1f1cc66a..de02ea85b27b7c23337c3bad8fe2a3e44290ed5d 100644 (file)
@@ -21,8 +21,8 @@ LL |     foo!(true);
    = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: if `bar` is a struct, use braces as delimiters
    |
-LL |         bar {  }
-   |             ~
+LL |         bar { baz: $rest }
+   |             ~            ~
 help: if `bar` is a function, use the arguments directly
    |
 LL -         bar(baz: $rest)
index 4737bc71860c24ef903af60947b32c449d636955..3cb6d75a6754b343c3be2e2ff72e7469038cb7a0 100644 (file)
@@ -2,8 +2,10 @@ error: this file contains an unclosed delimiter
   --> $DIR/issue-62973.rs:8:2
    |
 LL | fn p() { match s { v, E { [) {) }
-   |        -         - unclosed delimiter
-   |        |
+   |        -         -         -  - missing open `(` for this delimiter
+   |        |         |         |
+   |        |         |         missing open `(` for this delimiter
+   |        |         unclosed delimiter
    |        unclosed delimiter
 LL |
 LL |
@@ -13,8 +15,10 @@ error: this file contains an unclosed delimiter
   --> $DIR/issue-62973.rs:8:2
    |
 LL | fn p() { match s { v, E { [) {) }
-   |        -         - unclosed delimiter
-   |        |
+   |        -         -         -  - missing open `(` for this delimiter
+   |        |         |         |
+   |        |         |         missing open `(` for this delimiter
+   |        |         unclosed delimiter
    |        unclosed delimiter
 LL |
 LL |
index cfdd99d1434aef0f17965b4032a77111c9152e0d..a1f8a77ffa7c6cec978d163dbe15b1489b8341ed 100644 (file)
@@ -2,8 +2,9 @@ error: this file contains an unclosed delimiter
   --> $DIR/issue-63116.rs:3:18
    |
 LL | impl W <s(f;Y(;]
-   |          -       ^
-   |          |
+   |          -     - ^
+   |          |     |
+   |          |     missing open `[` for this delimiter
    |          unclosed delimiter
 
 error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `;`
index 8a16d7f955129811997464d47c4e10238db77340..0e8b0a5da220569b607fe3512ae59ee94e3fcf1b 100644 (file)
Binary files a/tests/ui/parser/issues/issue-66473.stderr and b/tests/ui/parser/issues/issue-66473.stderr differ
index b2c7dddc8011c21e1f3d21185bc48a97dbadf79c..43a903e6c4698e59840cdf18f73ed830c8b50c32 100644 (file)
Binary files a/tests/ui/parser/issues/issue-68629.stderr and b/tests/ui/parser/issues/issue-68629.stderr differ
index 6585a19d954efd39c15e3d7bd77ecb26e9796ae8..5bca5bbebeacb44984c8679e4d2c4757be4ee742 100644 (file)
Binary files a/tests/ui/parser/issues/issue-68730.stderr and b/tests/ui/parser/issues/issue-68730.stderr differ
diff --git a/tests/ui/parser/issues/issue-69259.rs b/tests/ui/parser/issues/issue-69259.rs
new file mode 100644 (file)
index 0000000..01fc2c0
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {}
+
+fn f) {} //~ ERROR unexpected closing delimiter
diff --git a/tests/ui/parser/issues/issue-69259.stderr b/tests/ui/parser/issues/issue-69259.stderr
new file mode 100644 (file)
index 0000000..604b7de
--- /dev/null
@@ -0,0 +1,8 @@
+error: unexpected closing delimiter: `)`
+  --> $DIR/issue-69259.rs:3:5
+   |
+LL | fn f) {}
+   |     ^ unexpected closing delimiter
+
+error: aborting due to previous error
+
index 39bf113ef83de58b648c2b9cd038ff58a2a178e4..46cbb056d1d880d798604ed18783d0e59da96856 100644 (file)
@@ -2,10 +2,10 @@ error: unexpected closing delimiter: `}`
   --> $DIR/issue-70583-block-is-empty-1.rs:20:1
    |
 LL | fn struct_generic(x: Vec<i32>) {
-   |                                - this opening brace...
+   |                                - this delimiter might not be properly closed...
 ...
 LL |     }
-   |     - ...matches this closing brace
+   |     - ...as it matches this but it has different indentation
 LL | }
    | ^ unexpected closing delimiter
 
index 5d37b216427f6b023c0389b70121018b39a62dbc..9ae94c701869b8c0effb6031d24b6ce51a6dba2d 100644 (file)
@@ -1,8 +1,12 @@
 error: unexpected closing delimiter: `}`
   --> $DIR/issue-70583-block-is-empty-2.rs:14:1
    |
+LL |         match self {
+   |                    - this delimiter might not be properly closed...
 LL |             ErrorHandled::Reported => {}}
-   |                                       -- block is empty, you might have not meant to close it
+   |                                       --- ...as it matches this but it has different indentation
+   |                                       |
+   |                                       block is empty, you might have not meant to close it
 ...
 LL | }
    | ^ unexpected closing delimiter
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 967a3e6fdc11b76a56a6f6cf88cf6eba459ad50a..689ce1eb6b70462c7f0f0c988efc73c3c2f0b1d5 100644 (file)
@@ -2,10 +2,10 @@ error: unexpected closing delimiter: `}`
   --> $DIR/macro-mismatched-delim-paren-brace.rs:5:1
    |
 LL | fn main() {
-   |           - this opening brace...
+   |           - this delimiter might not be properly closed...
 ...
 LL |     }
-   |     - ...matches this closing brace
+   |     - ...as it matches this but it has different indentation
 LL | }
    | ^ unexpected closing delimiter
 
diff --git a/tests/ui/parser/recover-unticked-labels.fixed b/tests/ui/parser/recover-unticked-labels.fixed
new file mode 100644 (file)
index 0000000..159d995
--- /dev/null
@@ -0,0 +1,7 @@
+// run-rustfix
+
+fn main() {
+    'label: loop { break 'label };    //~ error: cannot find value `label` in this scope
+    'label: loop { break 'label 0 };  //~ error: expected a label, found an identifier
+    'label: loop { continue 'label }; //~ error: expected a label, found an identifier
+}
diff --git a/tests/ui/parser/recover-unticked-labels.rs b/tests/ui/parser/recover-unticked-labels.rs
new file mode 100644 (file)
index 0000000..56034de
--- /dev/null
@@ -0,0 +1,7 @@
+// run-rustfix
+
+fn main() {
+    'label: loop { break label };    //~ error: cannot find value `label` in this scope
+    'label: loop { break label 0 };  //~ error: expected a label, found an identifier
+    'label: loop { continue label }; //~ error: expected a label, found an identifier
+}
diff --git a/tests/ui/parser/recover-unticked-labels.stderr b/tests/ui/parser/recover-unticked-labels.stderr
new file mode 100644 (file)
index 0000000..c115dff
--- /dev/null
@@ -0,0 +1,25 @@
+error: expected a label, found an identifier
+  --> $DIR/recover-unticked-labels.rs:5:26
+   |
+LL |     'label: loop { break label 0 };
+   |                          ^^^^^ help: labels start with a tick: `'label`
+
+error: expected a label, found an identifier
+  --> $DIR/recover-unticked-labels.rs:6:29
+   |
+LL |     'label: loop { continue label };
+   |                             ^^^^^ help: labels start with a tick: `'label`
+
+error[E0425]: cannot find value `label` in this scope
+  --> $DIR/recover-unticked-labels.rs:4:26
+   |
+LL |     'label: loop { break label };
+   |     ------               ^^^^^
+   |     |                    |
+   |     |                    not found in this scope
+   |     |                    help: use the similarly named label: `'label`
+   |     a label with a similar name exists
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
index cc04ac052040e30a37be98c8f17be97365dcf820..c41cda18743c81c37c7369a5d315bbf6ce749fae 100644 (file)
@@ -5,6 +5,8 @@ fn foo1(_: &dyn Drop + AsRef<str>) {} //~ ERROR ambiguous `+` in a type
 
 fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds
 
+fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds
+
 fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
 //~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{`
 //~| ERROR at least one trait is required for an object type
index 99c4515459d2e5166262754634394449e8ad031b..ccce3a8053e703c4e15030c576873eddc0abbb11 100644 (file)
@@ -13,17 +13,29 @@ LL | fn foo2(_: &dyn (Drop + AsRef<str>)) {}
 help: remove the parentheses
    |
 LL - fn foo2(_: &dyn (Drop + AsRef<str>)) {}
-LL + fn foo2(_: &dyn Drop + AsRef<str>) {}
+LL + fn foo2(_: &dyn  Drop + AsRef<str>) {}
+   |
+
+error: incorrect braces around trait bounds
+  --> $DIR/trait-object-delimiters.rs:8:25
+   |
+LL | fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {}
+   |                         ^                 ^
+   |
+help: remove the parentheses
+   |
+LL - fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {}
+LL + fn foo2_no_space(_: &dyn Drop + AsRef<str>) {}
    |
 
 error: expected parameter name, found `{`
-  --> $DIR/trait-object-delimiters.rs:8:17
+  --> $DIR/trait-object-delimiters.rs:10:17
    |
 LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
    |                 ^ expected parameter name
 
 error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{`
-  --> $DIR/trait-object-delimiters.rs:8:17
+  --> $DIR/trait-object-delimiters.rs:10:17
    |
 LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
    |                -^ expected one of 10 possible tokens
@@ -31,13 +43,13 @@ LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
    |                help: missing `,`
 
 error: expected identifier, found `<`
-  --> $DIR/trait-object-delimiters.rs:12:17
+  --> $DIR/trait-object-delimiters.rs:14:17
    |
 LL | fn foo4(_: &dyn <Drop + AsRef<str>>) {}
    |                 ^ expected identifier
 
 error: invalid `dyn` keyword
-  --> $DIR/trait-object-delimiters.rs:14:25
+  --> $DIR/trait-object-delimiters.rs:16:25
    |
 LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
    |                         ^^^ help: remove this keyword
@@ -56,13 +68,13 @@ LL | fn foo1(_: &dyn Drop + AsRef<str>) {}
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0224]: at least one trait is required for an object type
-  --> $DIR/trait-object-delimiters.rs:8:13
+  --> $DIR/trait-object-delimiters.rs:10:13
    |
 LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
    |             ^^^
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/trait-object-delimiters.rs:14:29
+  --> $DIR/trait-object-delimiters.rs:16:29
    |
 LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
    |                  ----       ^^^^^^^^^^ additional non-auto trait
@@ -72,7 +84,7 @@ LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Drop + AsRef<str> {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
 
 Some errors have detailed explanations: E0224, E0225.
 For more information about an error, try `rustc --explain E0224`.
index 89ae85ec990279bf489b4ab36471737e178e7972..cd25c7566897a752b2bb92223b7ba1aa11e02d83 100644 (file)
@@ -2,4 +2,11 @@ fn main() {
     let y = 0;
     //~^ ERROR unknown start of token: \u{37e}
     //~^^ HELP Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), but it is not
+        let x = 0;
+    //~^ ERROR unknown start of token: \u{a0}
+    //~^^ NOTE character appears 3 more times
+    //~^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not
+    let _ = 1 ⩵ 2;
+    //~^ ERROR unknown start of token
+    //~^^ HELP Unicode character '⩵' (Two Consecutive Equals Signs) looks like '==' (Double Equals Sign), but it is not
 }
index 0cfe9240e8514e65fb7ec186ff97069965c87581..086de5ec0997e82d34ced9cb6b4bcfb11b6d20bb 100644 (file)
@@ -9,5 +9,28 @@ help: Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), b
 LL |     let y = 0;
    |              ~
 
-error: aborting due to previous error
+error: unknown start of token: \u{a0}
+  --> $DIR/unicode-chars.rs:5:5
+   |
+LL |         let x = 0;
+   |     ^^^^
+   |
+   = note: character appears 3 more times
+help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not
+   |
+LL |         let x = 0;
+   |     ++++
+
+error: unknown start of token: \u{2a75}
+  --> $DIR/unicode-chars.rs:9:15
+   |
+LL |     let _ = 1 ⩵ 2;
+   |               ^
+   |
+help: Unicode character '⩵' (Two Consecutive Equals Signs) looks like '==' (Double Equals Sign), but it is not
+   |
+LL |     let _ = 1 == 2;
+   |               ~~
+
+error: aborting due to 3 previous errors
 
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
diff --git a/tests/ui/pattern/issue-106552.rs b/tests/ui/pattern/issue-106552.rs
new file mode 100644 (file)
index 0000000..aa2c141
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {
+    let 5 = 6;
+    //~^ error refutable pattern in local binding [E0005]
+
+    let x @ 5 = 6;
+    //~^ error refutable pattern in local binding [E0005]
+}
diff --git a/tests/ui/pattern/issue-106552.stderr b/tests/ui/pattern/issue-106552.stderr
new file mode 100644 (file)
index 0000000..ed5d40c
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0005]: refutable pattern in local binding
+  --> $DIR/issue-106552.rs:2:9
+   |
+LL |     let 5 = 6;
+   |         ^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+   = note: the matched value is of type `i32`
+help: you might want to use `if let` to ignore the variants that aren't matched
+   |
+LL |     if let 5 = 6 { todo!() }
+   |     ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL |     let _5 = 6;
+   |         +
+
+error[E0005]: refutable pattern in local binding
+  --> $DIR/issue-106552.rs:5:9
+   |
+LL |     let x @ 5 = 6;
+   |         ^^^^^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+   = note: the matched value is of type `i32`
+help: you might want to use `let else` to handle the variants that aren't matched
+   |
+LL |     let x @ 5 = 6 else { todo!() };
+   |                   ++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0005`.
index 282c411136922b17d69f88cf0c5105f817141736..13427d2c9b208cb923b66d92cd25800f23d8c2e0 100644 (file)
@@ -11,9 +11,9 @@ pub mod b {
     pub fn key(e: ::E) -> &'static str {
         match e {
             A => "A",
-//~^ WARN pattern binding `A` is named the same as one of the variants of the type `E`
+//~^ ERROR pattern binding `A` is named the same as one of the variants of the type `E`
             B => "B", //~ ERROR: unreachable pattern
-//~^ WARN pattern binding `B` is named the same as one of the variants of the type `E`
+//~^ ERROR pattern binding `B` is named the same as one of the variants of the type `E`
         }
     }
 }
index fc8ae1ed7b5b07e06812fbeb7766c3671afb96d4..7ea51b5f804c074abe85ce83a95ba042bbc67948 100644 (file)
@@ -1,12 +1,12 @@
-warning[E0170]: pattern binding `A` is named the same as one of the variants of the type `E`
+error[E0170]: pattern binding `A` is named the same as one of the variants of the type `E`
   --> $DIR/issue-14221.rs:13:13
    |
 LL |             A => "A",
    |             ^ help: to match on the variant, qualify the path: `E::A`
    |
-   = note: `#[warn(bindings_with_variant_name)]` on by default
+   = note: `#[deny(bindings_with_variant_name)]` on by default
 
-warning[E0170]: pattern binding `B` is named the same as one of the variants of the type `E`
+error[E0170]: pattern binding `B` is named the same as one of the variants of the type `E`
   --> $DIR/issue-14221.rs:15:13
    |
 LL |             B => "B",
@@ -27,6 +27,6 @@ note: the lint level is defined here
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error; 2 warnings emitted
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0170`.
index 6fd5768a5a26dd2e032ed6726fc13160155ef256..05d097eaf14e4a02a789cfc56f621dfedb80ad80 100644 (file)
@@ -1,7 +1,5 @@
 // Test for issue #67776: binding named the same as enum variant
-// should report a warning even when matching against a reference type
-
-// check-pass
+// should report an error even when matching against a reference type
 
 #![allow(unused_variables)]
 #![allow(non_snake_case)]
@@ -15,27 +13,27 @@ enum Foo {
 fn fn1(e: Foo) {
     match e {
         Bar => {},
-        //~^ WARNING named the same as one of the variants of the type `Foo`
+        //~^ ERROR named the same as one of the variants of the type `Foo`
         Baz => {},
-        //~^ WARNING named the same as one of the variants of the type `Foo`
+        //~^ ERROR named the same as one of the variants of the type `Foo`
     }
 }
 
 fn fn2(e: &Foo) {
     match e {
         Bar => {},
-        //~^ WARNING named the same as one of the variants of the type `Foo`
+        //~^ ERROR named the same as one of the variants of the type `Foo`
         Baz => {},
-        //~^ WARNING named the same as one of the variants of the type `Foo`
+        //~^ ERROR named the same as one of the variants of the type `Foo`
     }
 }
 
 fn fn3(e: &mut &&mut Foo) {
     match e {
         Bar => {},
-        //~^ WARNING named the same as one of the variants of the type `Foo`
+        //~^ ERROR named the same as one of the variants of the type `Foo`
         Baz => {},
-        //~^ WARNING named the same as one of the variants of the type `Foo`
+        //~^ ERROR named the same as one of the variants of the type `Foo`
     }
 }
 
index 6f3613b63c9aa4245f3b2460bdf1fdaa3779b57e..da580c7accb97c6574e1b0ae0af332b8fb073973 100644 (file)
@@ -1,41 +1,41 @@
-warning[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo`
-  --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:17:9
+error[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo`
+  --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:15:9
    |
 LL |         Bar => {},
    |         ^^^ help: to match on the variant, qualify the path: `Foo::Bar`
    |
-   = note: `#[warn(bindings_with_variant_name)]` on by default
+   = note: `#[deny(bindings_with_variant_name)]` on by default
 
-warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
-  --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:19:9
+error[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
+  --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:17:9
    |
 LL |         Baz => {},
    |         ^^^ help: to match on the variant, qualify the path: `Foo::Baz`
 
-warning[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo`
-  --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:26:9
+error[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo`
+  --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:24:9
    |
 LL |         Bar => {},
    |         ^^^ help: to match on the variant, qualify the path: `Foo::Bar`
 
-warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
-  --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:28:9
+error[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
+  --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:26:9
    |
 LL |         Baz => {},
    |         ^^^ help: to match on the variant, qualify the path: `Foo::Baz`
 
-warning[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo`
-  --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:35:9
+error[E0170]: pattern binding `Bar` is named the same as one of the variants of the type `Foo`
+  --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:33:9
    |
 LL |         Bar => {},
    |         ^^^ help: to match on the variant, qualify the path: `Foo::Bar`
 
-warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
-  --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:37:9
+error[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
+  --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:35:9
    |
 LL |         Baz => {},
    |         ^^^ help: to match on the variant, qualify the path: `Foo::Baz`
 
-warning: 6 warnings emitted
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0170`.
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()
+}
index 9c52ca422411619619b3aa74a3ee0c49b26d3046..de2c27a878c678688db5b389f07658344d79de47 100644 (file)
@@ -16,7 +16,7 @@ error: cannot find attribute `empty_helper` in this scope
 LL |             #[derive(GenHelperUse)]
    |                      ^^^^^^^^^^^^
    |
-   = note: consider importing this attribute macro:
+   = help: consider importing this attribute macro:
            empty_helper
    = note: this error originates in the derive macro `GenHelperUse` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -29,7 +29,7 @@ LL |         #[empty_helper]
 LL |             gen_helper_use!();
    |             ----------------- in this macro invocation
    |
-   = note: consider importing this attribute macro:
+   = help: consider importing this attribute macro:
            crate::empty_helper
    = note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index 901b3a951023c3505bbc3d3a952b9cb045765b83..700aac41c449a10890defc06ac3a17341ac3b100 100644 (file)
@@ -1,4 +1,6 @@
 // aux-build:expand-expr.rs
+// no-remap-src-base: check_expand_expr_file!() fails when enabled.
+
 #![feature(concat_bytes)]
 extern crate expand_expr;
 
@@ -8,7 +10,7 @@
 
 // Check builtin macros can be expanded.
 
-expand_expr_is!(11u32, line!());
+expand_expr_is!(13u32, line!());
 expand_expr_is!(24u32, column!());
 
 expand_expr_is!("Hello, World!", concat!("Hello, ", "World", "!"));
index 0004f2fe17f01ebfb65aaabbd86b376482eee382..df61e9972896b05734f2641b013bdbad66dc9539 100644 (file)
@@ -1,29 +1,29 @@
 error: expected one of `.`, `?`, or an operator, found `;`
-  --> $DIR/expand-expr.rs:106:27
+  --> $DIR/expand-expr.rs:108:27
    |
 LL | expand_expr_fail!("string"; hello);
    |                           ^ expected one of `.`, `?`, or an operator
 
 error: expected expression, found `$`
-  --> $DIR/expand-expr.rs:109:19
+  --> $DIR/expand-expr.rs:111:19
    |
 LL | expand_expr_fail!($);
    |                   ^ expected expression
 
 error: expected expression, found `$`
-  --> $DIR/expand-expr.rs:38:23
+  --> $DIR/expand-expr.rs:40:23
    |
 LL |     ($($t:tt)*) => { $($t)* };
    |                       ^^^^ expected expression
 
 error: expected expression, found `$`
-  --> $DIR/expand-expr.rs:111:28
+  --> $DIR/expand-expr.rs:113:28
    |
 LL | expand_expr_fail!(echo_pm!($));
    |                            ^ expected expression
 
 error: macro expansion ignores token `hello` and any following
-  --> $DIR/expand-expr.rs:115:47
+  --> $DIR/expand-expr.rs:117:47
    |
 LL | expand_expr_is!("string", echo_tts!("string"; hello));
    |                           --------------------^^^^^- caused by the macro expansion here
@@ -35,7 +35,7 @@ LL | expand_expr_is!("string", echo_tts!("string"; hello););
    |                                                     +
 
 error: macro expansion ignores token `;` and any following
-  --> $DIR/expand-expr.rs:116:44
+  --> $DIR/expand-expr.rs:118:44
    |
 LL | expand_expr_is!("string", echo_pm!("string"; hello));
    |                           -----------------^------- caused by the macro expansion here
@@ -47,7 +47,7 @@ LL | expand_expr_is!("string", echo_pm!("string"; hello););
    |                                                    +
 
 error: recursion limit reached while expanding `recursive_expand!`
-  --> $DIR/expand-expr.rs:124:16
+  --> $DIR/expand-expr.rs:126:16
    |
 LL | const _: u32 = recursive_expand!();
    |                ^^^^^^^^^^^^^^^^^^^
index 9eea630c310ecb1fc17900e7744332b240d4291b..471f317edf96479f64ac9bbc3beadf5d934aaf71 100644 (file)
 
 #[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
                                      //~| ERROR cannot find type `OuterDerive` in this scope
+                                     //~| WARN this was previously accepted
+                                     //~| WARN this was previously accepted
 struct Z;
 
 fn inner_block() {
     #[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
                                         //~| ERROR cannot find type `OuterDerive` in this scope
+                                        //~| WARN this was previously accepted
+                                        //~| WARN this was previously accepted
     struct InnerZ;
 }
 
-#[derive(generate_mod::CheckDeriveLint)] //~  ERROR cannot find type `OuterDeriveLint` in this scope
-                                         //~| ERROR cannot find type `FromOutside` in this scope
+#[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
 struct W;
 
 fn main() {}
index 64042ca0ecdea1e58a2541285084d901fce7b7c5..db629b5b5e239cc1f5557ea829988d2030597bf6 100644 (file)
@@ -4,7 +4,7 @@ error[E0412]: cannot find type `FromOutside` in this scope
 LL | generate_mod::check!();
    | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
    |
-   = note: consider importing this struct:
+   = help: consider importing this struct:
            FromOutside
    = note: this error originates in the macro `generate_mod::check` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -14,7 +14,7 @@ error[E0412]: cannot find type `Outer` in this scope
 LL | generate_mod::check!();
    | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
    |
-   = note: consider importing this struct:
+   = help: consider importing this struct:
            Outer
    = note: this error originates in the macro `generate_mod::check` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -24,7 +24,7 @@ error[E0412]: cannot find type `FromOutside` in this scope
 LL | #[generate_mod::check_attr]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
    |
-   = note: consider importing this struct:
+   = help: consider importing this struct:
            FromOutside
    = note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -34,70 +34,131 @@ error[E0412]: cannot find type `OuterAttr` in this scope
 LL | #[generate_mod::check_attr]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
    |
-   = note: consider importing this struct:
+   = help: consider importing this struct:
            OuterAttr
    = note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0412]: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
   --> $DIR/generate-mod.rs:16:10
    |
 LL | #[derive(generate_mod::CheckDerive)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
    |
-   = note: consider importing this struct:
-           FromOutside
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
    = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0412]: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
   --> $DIR/generate-mod.rs:16:10
    |
 LL | #[derive(generate_mod::CheckDerive)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
    |
-   = note: consider importing this struct:
-           OuterDerive
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
    = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0412]: cannot find type `FromOutside` in this scope
-  --> $DIR/generate-mod.rs:21:14
+error: cannot find type `FromOutside` in this scope
+  --> $DIR/generate-mod.rs:23:14
    |
 LL |     #[derive(generate_mod::CheckDerive)]
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
    |
-   = note: consider importing this struct:
-           FromOutside
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
    = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0412]: cannot find type `OuterDerive` in this scope
-  --> $DIR/generate-mod.rs:21:14
+error: cannot find type `OuterDerive` in this scope
+  --> $DIR/generate-mod.rs:23:14
    |
 LL |     #[derive(generate_mod::CheckDerive)]
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
    |
-   = note: consider importing this struct:
-           OuterDerive
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
    = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0412]: cannot find type `FromOutside` in this scope
-  --> $DIR/generate-mod.rs:26:10
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
+Future incompatibility report: Future breakage diagnostic:
+error: cannot find type `FromOutside` in this scope
+  --> $DIR/generate-mod.rs:16:10
    |
-LL | #[derive(generate_mod::CheckDeriveLint)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+LL | #[derive(generate_mod::CheckDerive)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
    |
-   = note: consider importing this struct:
-           FromOutside
-   = note: this error originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+Future breakage diagnostic:
+error: cannot find type `OuterDerive` in this scope
+  --> $DIR/generate-mod.rs:16:10
+   |
+LL | #[derive(generate_mod::CheckDerive)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0412]: cannot find type `OuterDeriveLint` in this scope
-  --> $DIR/generate-mod.rs:26:10
+Future breakage diagnostic:
+error: cannot find type `FromOutside` in this scope
+  --> $DIR/generate-mod.rs:23:14
    |
-LL | #[derive(generate_mod::CheckDeriveLint)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+LL |     #[derive(generate_mod::CheckDerive)]
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
    |
-   = note: consider importing this struct:
-           OuterDeriveLint
-   = note: this error originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 10 previous errors
+Future breakage diagnostic:
+error: cannot find type `OuterDerive` in this scope
+  --> $DIR/generate-mod.rs:23:14
+   |
+LL |     #[derive(generate_mod::CheckDerive)]
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+Future breakage diagnostic:
+warning: cannot find type `FromOutside` in this scope
+  --> $DIR/generate-mod.rs:30:10
+   |
+LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
+note: the lint level is defined here
+  --> $DIR/generate-mod.rs:30:10
+   |
+LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+Future breakage diagnostic:
+warning: cannot find type `OuterDeriveLint` in this scope
+  --> $DIR/generate-mod.rs:30:10
+   |
+LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
+note: the lint level is defined here
+  --> $DIR/generate-mod.rs:30:10
+   |
+LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-For more information about this error, try `rustc --explain E0412`.
index ab5013848891e549c8682a1fd89d234d5f729865..873054927c96279723f7b87ae31a908372109ca1 100644 (file)
@@ -1,5 +1,5 @@
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL | enum ProceduralMasqueradeDummyType {
    = note: `#[deny(proc_macro_back_compat)]` on by default
 
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL | enum ProceduralMasqueradeDummyType {
    = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
 
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -30,7 +30,7 @@ LL | enum ProceduralMasqueradeDummyType {
    = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
 
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL | enum ProceduralMasqueradeDummyType {
    = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
 
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@ LL | enum ProceduralMasqueradeDummyType {
    = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
 
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL | enum ProceduralMasqueradeDummyType {
    = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
 
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -70,7 +70,7 @@ LL | enum ProceduralMasqueradeDummyType {
    = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
 
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -83,7 +83,7 @@ error: aborting due to 8 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -95,7 +95,7 @@ LL | enum ProceduralMasqueradeDummyType {
 
 Future breakage diagnostic:
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -107,7 +107,7 @@ LL | enum ProceduralMasqueradeDummyType {
 
 Future breakage diagnostic:
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -119,7 +119,7 @@ LL | enum ProceduralMasqueradeDummyType {
 
 Future breakage diagnostic:
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -131,7 +131,7 @@ LL | enum ProceduralMasqueradeDummyType {
 
 Future breakage diagnostic:
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -143,7 +143,7 @@ LL | enum ProceduralMasqueradeDummyType {
 
 Future breakage diagnostic:
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -155,7 +155,7 @@ LL | enum ProceduralMasqueradeDummyType {
 
 Future breakage diagnostic:
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -167,7 +167,7 @@ LL | enum ProceduralMasqueradeDummyType {
 
 Future breakage diagnostic:
 error: using an old version of `rental`
-  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 61ca53b28d40d850caf6858fc8a41fcb4b02b9ac..3d793d2a0145c984f27fa8092f21df04c2ba724e 100644 (file)
@@ -3,21 +3,21 @@ PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
-        span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:1: 4:5 (#0),
+        span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:1: 4:5 (#0),
     },
     Ident {
         ident: "ProceduralMasqueradeDummyType",
-        span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6: 4:35 (#0),
+        span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6: 4:35 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "Input",
-                span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:13:5: 13:10 (#0),
+                span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:13:5: 13:10 (#0),
             },
         ],
-        span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:36: 14:2 (#0),
+        span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:36: 14:2 (#0),
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, }
@@ -25,20 +25,20 @@ PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
-        span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:1: 4:5 (#0),
+        span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:1: 4:5 (#0),
     },
     Ident {
         ident: "ProceduralMasqueradeDummyType",
-        span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6: 4:35 (#0),
+        span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6: 4:35 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "Input",
-                span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:13:5: 13:10 (#0),
+                span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:13:5: 13:10 (#0),
             },
         ],
-        span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:36: 14:2 (#0),
+        span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:36: 14:2 (#0),
     },
 ]
index e9ff66ba45a08194678ad1ddb7f8135952dd4cfa..24a389c450ea01d176cab209eb54b3cf4430c8cf 100644 (file)
@@ -1,11 +1,8 @@
 // aux-build:test-macros.rs
 // compile-flags: -Z span-debug
 // revisions: local remapped
-// [remapped]compile-flags: --remap-path-prefix={{src-base}}=remapped
-
-// The remapped paths are not normalized by compiletest.
-// normalize-stdout-test: "\\(proc-macro|pretty-print-hack)" -> "/$1"
-// normalize-stderr-test: "\\(proc-macro|pretty-print-hack)" -> "/$1"
+// [local] no-remap-src-base: The hack should work regardless of remapping.
+// [remapped] remap-src-base
 
 #![no_std] // Don't load unnecessary hygiene information from std
 extern crate std;
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
 
diff --git a/tests/ui/remap-path-prefix.rs b/tests/ui/remap-path-prefix.rs
deleted file mode 100644 (file)
index 2eef970..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-// compile-flags: --remap-path-prefix={{src-base}}=remapped
-
-fn main() {
-    // We cannot actually put an ERROR marker here because
-    // the file name in the error message is not what the
-    // test framework expects (since the filename gets remapped).
-    // We still test the expected error in the stderr file.
-    ferris
-}
diff --git a/tests/ui/remap-path-prefix.stderr b/tests/ui/remap-path-prefix.stderr
deleted file mode 100644 (file)
index ad6a35d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0425]: cannot find value `ferris` in this scope
-  --> remapped/remap-path-prefix.rs:8:5
-   |
-LL |     ferris
-   |     ^^^^^^ not found in this scope
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0425`.
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 761089cd3871a7ead4a8ea5f45d85b531d89c029..122e8fd350cb2f4ef15abc373500f807536b0488 100644 (file)
@@ -7,9 +7,9 @@ LL | use alloc;
 help: consider importing one of these items instead
    |
 LL | use core::alloc;
-   |     ~~~~~~~~~~~~
-LL | use std::alloc;
    |     ~~~~~~~~~~~
+LL | use std::alloc;
+   |     ~~~~~~~~~~
 
 error: aborting due to previous error
 
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 0b3de0df2b884827195dca2cb8c2623cf5ddb763..d2254acb33f6bc87f9e1bd6677cb1d889e1b8b9c 100644 (file)
@@ -365,4 +365,24 @@ union BeeWhereAyTeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: 'a + Debu
     }
 }
 
+// https://github.com/rust-lang/rust/issues/106870
+mod multiple_predicates_with_same_span {
+    macro_rules! m {
+        ($($name:ident)+) => {
+            struct Inline<'a, $($name: 'a,)+>(&'a ($($name,)+));
+            //~^ ERROR: outlives requirements can be inferred
+            struct FullWhere<'a, $($name,)+>(&'a ($($name,)+)) where $($name: 'a,)+;
+            //~^ ERROR: outlives requirements can be inferred
+            struct PartialWhere<'a, $($name,)+>(&'a ($($name,)+)) where (): Sized, $($name: 'a,)+;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Interleaved<'a, $($name,)+>(&'a ($($name,)+))
+            where
+                (): Sized,
+                $($name: 'a, $name: 'a, )+ //~ ERROR: outlives requirements can be inferred
+                $($name: 'a, $name: 'a, )+;
+        }
+    }
+    m!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15);
+}
+
 fn main() {}
index 251d74094caa94ed087024235ee178116f9d7810..f5ec287d29132dbce156642d9f410390618b266d 100644 (file)
@@ -819,5 +819,61 @@ LL -     union BeeWhereAyTeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U:
 LL +     union BeeWhereAyTeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: Debug,  {
    |
 
-error: aborting due to 68 previous errors
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-multispan.rs:372:38
+   |
+LL |             struct Inline<'a, $($name: 'a,)+>(&'a ($($name,)+));
+   |                                      ^^^^ help: remove these bounds
+...
+LL |     m!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15);
+   |     --------------------------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-multispan.rs:374:64
+   |
+LL |             struct FullWhere<'a, $($name,)+>(&'a ($($name,)+)) where $($name: 'a,)+;
+   |                                                                ^^^^^^^^^^^^^^^^^^ help: remove these bounds
+...
+LL |     m!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15);
+   |     --------------------------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-multispan.rs:376:86
+   |
+LL |             struct PartialWhere<'a, $($name,)+>(&'a ($($name,)+)) where (): Sized, $($name: 'a,)+;
+   |                                                                                      ^^^^^^^^^ help: remove these bounds
+...
+LL |     m!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15);
+   |     --------------------------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-multispan.rs:381:19
+   |
+LL |                 $($name: 'a, $name: 'a, )+
+   |                   ^^^^^^^^^  ^^^^^^^^^
+LL |                 $($name: 'a, $name: 'a, )+;
+   |                   ^^^^^^^^^  ^^^^^^^^^
+...
+LL |     m!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15);
+   |     ---------------------------------------------------------
+   |     |
+   |     in this macro invocation
+   |     in this macro invocation
+   |     in this macro invocation
+   |     in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: remove these bounds
+   |
+LL ~                 $(, , )+
+LL ~                 $(, , )+;
+   |
+
+error: aborting due to 72 previous errors
 
index 13645244da069b3e20369fe5877993f2e4e51931..868bdf2e068d807861af109f76da061301ab731d 100644 (file)
@@ -791,5 +791,14 @@ struct StaticRef<T: 'static> {
     field: &'static T
 }
 
+struct TrailingCommaInWhereClause<'a, T, U>
+where
+    T: 'a,
+    
+    //~^ ERROR outlives requirements can be inferred
+{
+    tee: T,
+    yoo: &'a U
+}
 
 fn main() {}
index d9486ba66f8aa236ff01d364281591550d7aff5d..75783764ad6c9365f6bd506b99be9239218fb1d3 100644 (file)
@@ -791,5 +791,14 @@ struct StaticRef<T: 'static> {
     field: &'static T
 }
 
+struct TrailingCommaInWhereClause<'a, T, U>
+where
+    T: 'a,
+    U: 'a,
+    //~^ ERROR outlives requirements can be inferred
+{
+    tee: T,
+    yoo: &'a U
+}
 
 fn main() {}
index faa9f21e38ba23c0e91355419bb5b6de92187c5e..e655fb4842c714613724c98205f0050669c89698 100644 (file)
@@ -1,8 +1,8 @@
 error: outlives requirements can be inferred
-  --> $DIR/edition-lint-infer-outlives.rs:26:31
+  --> $DIR/edition-lint-infer-outlives.rs:797:5
    |
-LL |     struct TeeOutlivesAy<'a, T: 'a> {
-   |                               ^^^^ help: remove this bound
+LL |     U: 'a,
+   |     ^^^^^^ help: remove this bound
    |
 note: the lint level is defined here
   --> $DIR/edition-lint-infer-outlives.rs:4:9
@@ -10,6 +10,12 @@ note: the lint level is defined here
 LL | #![deny(explicit_outlives_requirements)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives.rs:26:31
+   |
+LL |     struct TeeOutlivesAy<'a, T: 'a> {
+   |                               ^^^^ help: remove this bound
+
 error: outlives requirements can be inferred
   --> $DIR/edition-lint-infer-outlives.rs:31:40
    |
@@ -916,5 +922,5 @@ error: outlives requirements can be inferred
 LL |     union BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where 'b: 'a, T: Debug {
    |                                                            ^^^^^^^^ help: remove this bound
 
-error: aborting due to 152 previous errors
+error: aborting due to 153 previous errors
 
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 8881ede0dbca7e362d5f3cf92fb1444fa2a2520c..f8b3e6d65afb64cac3492bf2a9f27b11cd58b813 100644 (file)
@@ -15,7 +15,7 @@ LL | use std::simd::intrinsics;
 help: consider importing this module instead
    |
 LL | use std::intrinsics;
-   |     ~~~~~~~~~~~~~~~~
+   |     ~~~~~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/single-use-lifetime/issue-104440.rs b/tests/ui/single-use-lifetime/issue-104440.rs
new file mode 100644 (file)
index 0000000..0795e95
--- /dev/null
@@ -0,0 +1,100 @@
+#![feature(decl_macro, rustc_attrs)]
+#![deny(single_use_lifetimes)]
+
+mod type_params {
+    macro m($T:ident) {
+        fn f<$T: Clone, T: PartialEq>(t1: $T, t2: T) -> ($T, bool) {
+            (t1.clone(), t2 == t2)
+        }
+    }
+
+    #[rustc_macro_transparency = "semitransparent"]
+    macro n($T:ident) {
+        fn g<$T: Clone>(t1: $T, t2: T) -> (T, $T) {
+            (t1.clone(), t2.clone())
+        }
+        fn h<T: Clone>(t1: $T, t2: T) -> (T, $T) {
+            (t1.clone(), t2.clone())
+        }
+    }
+
+    #[rustc_macro_transparency = "transparent"]
+    macro p($T:ident) {
+        fn j<$T: Clone>(t1: $T, t2: T) -> (T, $T) {
+            (t1.clone(), t2.clone())
+        }
+        fn k<T: Clone>(t1: $T, t2: T) -> (T, $T) {
+            (t1.clone(), t2.clone())
+        }
+    }
+
+    m!(T);
+    n!(T);
+    p!(T);
+}
+
+mod lifetime_params {
+    macro m($a:lifetime) {
+        fn f<'b, 'c, $a: 'b, 'a: 'c>(t1: &$a(), t2: &'a ()) -> (&'b (), &'c ()) { //~ ERROR lifetime parameter `'a` only used once
+            (t1, t2)
+        }
+    }
+
+    #[rustc_macro_transparency = "semitransparent"]
+    macro n($a:lifetime) {
+        fn g<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) {
+            (t1, t2)
+        }
+        fn h<'a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) {
+            (t1, t2)
+        }
+    }
+
+    #[rustc_macro_transparency = "transparent"]
+    macro p($a:lifetime) {
+        fn j<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) {
+            (t1, t2)
+        }
+        fn k<'a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) {
+            (t1, t2)
+        }
+    }
+
+    m!('a); //~ ERROR lifetime parameter `'a` only used once
+    n!('a);
+    p!('a);
+}
+
+mod const_params {
+    macro m($C:ident) {
+        fn f<const $C: usize, const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); $C], [(); C]) {
+            (t1, t2)
+        }
+    }
+
+    #[rustc_macro_transparency = "semitransparent"]
+    macro n($C:ident) {
+        fn g<const $C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) {
+            (t1, t2)
+        }
+        fn h<const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) {
+            (t1, t2)
+        }
+    }
+
+    #[rustc_macro_transparency = "transparent"]
+    macro p($C:ident) {
+        fn j<const $C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) {
+            (t1, t2)
+        }
+        fn k<const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) {
+            (t1, t2)
+        }
+    }
+
+    m!(C);
+    n!(C);
+    p!(C);
+}
+
+fn main() {}
diff --git a/tests/ui/single-use-lifetime/issue-104440.stderr b/tests/ui/single-use-lifetime/issue-104440.stderr
new file mode 100644 (file)
index 0000000..54ded31
--- /dev/null
@@ -0,0 +1,28 @@
+error: lifetime parameter `'a` only used once
+  --> $DIR/issue-104440.rs:63:8
+   |
+LL |     m!('a);
+   |        ^^
+   |        |
+   |        this lifetime...
+   |        ...is used only here
+   |
+note: the lint level is defined here
+  --> $DIR/issue-104440.rs:2:9
+   |
+LL | #![deny(single_use_lifetimes)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime parameter `'a` only used once
+  --> $DIR/issue-104440.rs:38:30
+   |
+LL |         fn f<'b, 'c, $a: 'b, 'a: 'c>(t1: &$a(), t2: &'a ()) -> (&'b (), &'c ()) {
+   |                              ^^ this lifetime...     -- ...is used only here
+...
+LL |     m!('a);
+   |     ------ in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
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 |     };
diff --git a/tests/ui/stability-attribute/issue-106589.rs b/tests/ui/stability-attribute/issue-106589.rs
new file mode 100644 (file)
index 0000000..3cad9a3
--- /dev/null
@@ -0,0 +1,10 @@
+// #![feature(staged_api)] // note: `staged_api` not enabled
+
+#![stable(feature = "foo", since = "1.0.0")]
+//~^ ERROR stability attributes may not be used outside of the standard library
+
+#[unstable(feature = "foo", issue = "none")]
+//~^ ERROR stability attributes may not be used outside of the standard library
+fn foo_unstable() {}
+
+fn main() {}
diff --git a/tests/ui/stability-attribute/issue-106589.stderr b/tests/ui/stability-attribute/issue-106589.stderr
new file mode 100644 (file)
index 0000000..ccf3f71
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0734]: stability attributes may not be used outside of the standard library
+  --> $DIR/issue-106589.rs:6:1
+   |
+LL | #[unstable(feature = "foo", issue = "none")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0734]: stability attributes may not be used outside of the standard library
+  --> $DIR/issue-106589.rs:3:1
+   |
+LL | #![stable(feature = "foo", since = "1.0.0")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0734`.
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
    |
index 44a39efdf25425015543ec99292f7e9c78ad7ed3..bc097bf6eb4515f76396ffff7b467a1721cbf5e5 100644 (file)
@@ -11,6 +11,13 @@ LL |     let _: Option<(i32, bool)> = Some(1, 2);
    |                                       ^
    = note: expected tuple `(i32, bool)`
                found type `{integer}`
+help: the type constructed contains `{integer}` due to the type of the argument passed
+  --> $DIR/args-instead-of-tuple-errors.rs:6:34
+   |
+LL |     let _: Option<(i32, bool)> = Some(1, 2);
+   |                                  ^^^^^-^^^^
+   |                                       |
+   |                                       this argument influences the type of `Some`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: remove the extra argument
@@ -64,6 +71,13 @@ LL |     let _: Option<(i32,)> = Some(5_usize);
    |
    = note: expected tuple `(i32,)`
                found type `usize`
+help: the type constructed contains `usize` due to the type of the argument passed
+  --> $DIR/args-instead-of-tuple-errors.rs:14:29
+   |
+LL |     let _: Option<(i32,)> = Some(5_usize);
+   |                             ^^^^^-------^
+   |                                  |
+   |                                  this argument influences the type of `Some`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
@@ -77,6 +91,13 @@ LL |     let _: Option<(i32,)> = Some((5_usize));
    |
    = note: expected tuple `(i32,)`
                found type `usize`
+help: the type constructed contains `usize` due to the type of the argument passed
+  --> $DIR/args-instead-of-tuple-errors.rs:17:29
+   |
+LL |     let _: Option<(i32,)> = Some((5_usize));
+   |                             ^^^^^---------^
+   |                                  |
+   |                                  this argument influences the type of `Some`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
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 {
diff --git a/tests/ui/suggestions/call-on-unimplemented-with-autoderef.rs b/tests/ui/suggestions/call-on-unimplemented-with-autoderef.rs
new file mode 100644 (file)
index 0000000..9021dd7
--- /dev/null
@@ -0,0 +1,13 @@
+trait Foo {}
+
+impl Foo for i32 {}
+
+fn needs_foo(_: impl Foo) {}
+
+fn test(x: &Box<dyn Fn() -> i32>) {
+    needs_foo(x);
+    //~^ ERROR the trait bound
+    //~| HELP use parentheses to call this trait object
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/call-on-unimplemented-with-autoderef.stderr b/tests/ui/suggestions/call-on-unimplemented-with-autoderef.stderr
new file mode 100644 (file)
index 0000000..90f44cc
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `&Box<dyn Fn() -> i32>: Foo` is not satisfied
+  --> $DIR/call-on-unimplemented-with-autoderef.rs:8:15
+   |
+LL |     needs_foo(x);
+   |     --------- ^ the trait `Foo` is not implemented for `&Box<dyn Fn() -> i32>`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `needs_foo`
+  --> $DIR/call-on-unimplemented-with-autoderef.rs:5:22
+   |
+LL | fn needs_foo(_: impl Foo) {}
+   |                      ^^^ required by this bound in `needs_foo`
+help: use parentheses to call this trait object
+   |
+LL |     needs_foo(x());
+   |                ++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 477eb2786799a5d9320e5ed5b210dfef659c3af8..2af7c2f6971484e925eafdc4d402dbf0de7be0c6 100644 (file)
@@ -24,16 +24,7 @@ error[E0425]: cannot find value `F` in this scope
   --> $DIR/constrain-suggest-ice.rs:6:9
    |
 LL |         F
-   |         ^
-   |
-help: a local variable with a similar name exists
-   |
-LL |         x
-   |         ~
-help: you might be missing a type parameter
-   |
-LL | struct Bug<S, F>{
-   |             +++
+   |         ^ help: a local variable with a similar name exists: `x`
 
 error: generic `Self` types are currently not permitted in anonymous constants
   --> $DIR/constrain-suggest-ice.rs:3:21
index e63210a3e987efd7c8bf7e1549b15b0aa8e01e0c..d161ed284f6d9dd292ce523ffb1ebaa99e4c7e67 100644 (file)
@@ -1,9 +1,8 @@
 #![allow(unused, nonstandard_style)]
-#![deny(bindings_with_variant_name)]
 
 // If an enum has two different variants,
 // then it cannot be matched upon in a function argument.
-// It still gets a warning, but no suggestions.
+// It still gets an error, but no suggestions.
 enum Foo {
     C,
     D,
index eb22b0ea5c83da68b71dbe18c4752664f228331f..0bd1b7ba4bacfdbe35e8f85a82a2b8b96fe115ac 100644 (file)
@@ -1,17 +1,13 @@
 error[E0170]: pattern binding `C` is named the same as one of the variants of the type `Foo`
-  --> $DIR/issue-88730.rs:12:8
+  --> $DIR/issue-88730.rs:11:8
    |
 LL | fn foo(C: Foo) {}
    |        ^
    |
-note: the lint level is defined here
-  --> $DIR/issue-88730.rs:2:9
-   |
-LL | #![deny(bindings_with_variant_name)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[deny(bindings_with_variant_name)]` on by default
 
 error[E0170]: pattern binding `C` is named the same as one of the variants of the type `Foo`
-  --> $DIR/issue-88730.rs:15:9
+  --> $DIR/issue-88730.rs:14:9
    |
 LL |     let C = Foo::D;
    |         ^
diff --git a/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.rs b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.rs
new file mode 100644 (file)
index 0000000..3bf6b7b
--- /dev/null
@@ -0,0 +1,28 @@
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::rc::Rc;
+
+pub struct Trader<'a> {
+    closure: Box<dyn Fn(&mut Trader) + 'a>,
+}
+
+impl<'a> Trader<'a> {
+    pub fn new() -> Self {
+        Trader {
+            closure: Box::new(|_| {}),
+        }
+    }
+    pub fn set_closure(&mut self, function: impl Fn(&mut Trader) + 'a) {
+        //foo
+    }
+}
+
+fn main() {
+    let closure = |trader : Trader| {
+        println!("Woooosh!");
+    };
+
+    let mut trader = Trader::new();
+    trader.set_closure(closure);
+    //~^ ERROR type mismatch in closure arguments
+}
diff --git a/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr
new file mode 100644 (file)
index 0000000..6820af1
--- /dev/null
@@ -0,0 +1,26 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/late-bound-in-borrow-closure-sugg.rs:26:24
+   |
+LL |     let closure = |trader : Trader| {
+   |                   ----------------- found signature defined here
+...
+LL |     trader.set_closure(closure);
+   |            ----------- ^^^^^^^ expected due to this
+   |            |
+   |            required by a bound introduced by this call
+   |
+   = note: expected closure signature `for<'a, 'b> fn(&'a mut Trader<'b>) -> _`
+              found closure signature `for<'a> fn(Trader<'a>) -> _`
+note: required by a bound in `Trader::<'a>::set_closure`
+  --> $DIR/late-bound-in-borrow-closure-sugg.rs:15:50
+   |
+LL |     pub fn set_closure(&mut self, function: impl Fn(&mut Trader) + 'a) {
+   |                                                  ^^^^^^^^^^^^^^^ required by this bound in `Trader::<'a>::set_closure`
+help: consider borrowing the argument
+   |
+LL |     let closure = |trader : &mut Trader| {
+   |                             ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0631`.
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
index 5f59d0f541c99433e116610108335abbe02e9a0c..7f05832bcd7281e77c2b53d06549e36d9636a612 100644 (file)
@@ -8,6 +8,13 @@ LL |     let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
    |
    = note: expected reference `&str`
                 found closure `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]`
+help: the return type of this call is `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]` due to the type of the argument passed
+  --> $DIR/sugg-else-for-closure.rs:6:14
+   |
+LL |     let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
+   |              ^^^^^^^^^^^^-------------------------------^
+   |                          |
+   |                          this argument influences the return type of `unwrap_or`
 note: associated function defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: try calling `unwrap_or_else` instead
diff --git a/tests/ui/suggestions/suggest-remove-deref.fixed b/tests/ui/suggestions/suggest-remove-deref.fixed
new file mode 100644 (file)
index 0000000..4dc12da
--- /dev/null
@@ -0,0 +1,28 @@
+// run-rustfix
+
+//issue #106496
+
+struct S;
+
+trait X {}
+impl X for S {}
+
+fn foo<T: X>(_: &T) {}
+fn test_foo() {
+    let hello = &S;
+    foo(hello);
+    //~^ ERROR mismatched types
+}
+
+fn bar(_: &String) {}
+fn test_bar() {
+    let v = String::from("hello");
+    let s = &v;
+    bar(s);
+    //~^ ERROR mismatched types
+}
+
+fn main() {
+    test_foo();
+    test_bar();
+}
diff --git a/tests/ui/suggestions/suggest-remove-deref.rs b/tests/ui/suggestions/suggest-remove-deref.rs
new file mode 100644 (file)
index 0000000..c2d385c
--- /dev/null
@@ -0,0 +1,28 @@
+// run-rustfix
+
+//issue #106496
+
+struct S;
+
+trait X {}
+impl X for S {}
+
+fn foo<T: X>(_: &T) {}
+fn test_foo() {
+    let hello = &S;
+    foo(*hello);
+    //~^ ERROR mismatched types
+}
+
+fn bar(_: &String) {}
+fn test_bar() {
+    let v = String::from("hello");
+    let s = &v;
+    bar(*s);
+    //~^ ERROR mismatched types
+}
+
+fn main() {
+    test_foo();
+    test_bar();
+}
diff --git a/tests/ui/suggestions/suggest-remove-deref.stderr b/tests/ui/suggestions/suggest-remove-deref.stderr
new file mode 100644 (file)
index 0000000..f5d810e
--- /dev/null
@@ -0,0 +1,43 @@
+error[E0308]: mismatched types
+  --> $DIR/suggest-remove-deref.rs:13:9
+   |
+LL |     foo(*hello);
+   |     --- ^^^^^^ expected reference, found struct `S`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected reference `&_`
+                 found struct `S`
+note: function defined here
+  --> $DIR/suggest-remove-deref.rs:10:4
+   |
+LL | fn foo<T: X>(_: &T) {}
+   |    ^^^       -----
+help: consider removing deref here
+   |
+LL -     foo(*hello);
+LL +     foo(hello);
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-remove-deref.rs:21:9
+   |
+LL |     bar(*s);
+   |     --- ^^ expected `&String`, found struct `String`
+   |     |
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/suggest-remove-deref.rs:17:4
+   |
+LL | fn bar(_: &String) {}
+   |    ^^^ ----------
+help: consider removing deref here
+   |
+LL -     bar(*s);
+LL +     bar(s);
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/suggestions/type-mismatch-byte-literal.rs b/tests/ui/suggestions/type-mismatch-byte-literal.rs
new file mode 100644 (file)
index 0000000..34199f8
--- /dev/null
@@ -0,0 +1,18 @@
+// Tests that a suggestion is issued for type mismatch errors when a
+// u8 is expected and a char literal which is ASCII is supplied.
+
+fn foo(_t: u8) {}
+
+fn main() {
+    let _x: u8 = 'X';
+    //~^ ERROR: mismatched types [E0308]
+    //~| HELP: if you meant to write a byte literal, prefix with `b`
+
+    foo('#');
+    //~^ ERROR: mismatched types [E0308]
+    //~| HELP: if you meant to write a byte literal, prefix with `b`
+
+    // Do not issue the suggestion if the char literal isn't ASCII
+    let _t: u8 = '€';
+    //~^ ERROR: mismatched types [E0308]
+}
diff --git a/tests/ui/suggestions/type-mismatch-byte-literal.stderr b/tests/ui/suggestions/type-mismatch-byte-literal.stderr
new file mode 100644 (file)
index 0000000..c9c2e74
--- /dev/null
@@ -0,0 +1,42 @@
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch-byte-literal.rs:7:18
+   |
+LL |     let _x: u8 = 'X';
+   |             --   ^^^ expected `u8`, found `char`
+   |             |
+   |             expected due to this
+   |
+help: if you meant to write a byte literal, prefix with `b`
+   |
+LL |     let _x: u8 = b'X';
+   |                  ~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch-byte-literal.rs:11:9
+   |
+LL |     foo('#');
+   |     --- ^^^ expected `u8`, found `char`
+   |     |
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/type-mismatch-byte-literal.rs:4:4
+   |
+LL | fn foo(_t: u8) {}
+   |    ^^^ ------
+help: if you meant to write a byte literal, prefix with `b`
+   |
+LL |     foo(b'#');
+   |         ~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch-byte-literal.rs:16:18
+   |
+LL |     let _t: u8 = '€';
+   |             --   ^^^ expected `u8`, found `char`
+   |             |
+   |             expected due to this
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 3ad4ed24cf7fc7e09dff18e4a6183dd4160750ff..fe490a6000d7bc6eaabd936c7f0fc8d1555f47c3 100644 (file)
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN5basic4main17hcbad207c0eeb0b3bE)
+error: symbol-name(_ZN5basic4main17he9f658e438f1cac0E)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(basic::main::hcbad207c0eeb0b3b)
+error: demangling(basic::main::he9f658e438f1cac0)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
index 08add29cb9cd521431521e535f764ff47fbd41d7..81aba403d0ba2cecb2bcf17238c207d46bdfd003 100644 (file)
@@ -8,9 +8,8 @@ trait Foo {
 }
 
 impl Foo for [u8; 1 + 2] {
-    #[rustc_def_path] //~ ERROR def-path(<[u8; _] as Foo>::baz)
-    fn baz() { }
+    #[rustc_def_path] //~ ERROR def-path(<[u8; 1 + 2] as Foo>::baz)
+    fn baz() {}
 }
 
-fn main() {
-}
+fn main() {}
index 98330031602233859d6d2fbe6980a17881c5f0ef..0c3205e0108e66e50589e2bab2b702537991b76e 100644 (file)
@@ -1,4 +1,4 @@
-error: def-path(<[u8; _] as Foo>::baz)
+error: def-path(<[u8; 1 + 2] as Foo>::baz)
   --> $DIR/impl2.rs:11:5
    |
 LL |     #[rustc_def_path]
index 21bf21ee71c6ff9a3697e87fb38983f7f1a7e9bd..29b42f48d803a09ccd6ee8d036daf65e909e3f8e 100644 (file)
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h2f2efcf580c9b1eeE)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h13209029be24b923E)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h2f2efcf580c9b1ee)
+error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h13209029be24b923)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
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 a45c5bd45880fde209a40cb74048715bf0a58c05..7635f579d66b94cd9e2ce76388f132e3517d1fee 100644 (file)
@@ -13,7 +13,7 @@ LL | use test as y;
 help: consider importing this module instead
    |
 LL | use test::test as y;
-   |     ~~~~~~~~~~~~~~~~
+   |     ~~~~~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/thir-print/thir-flat.rs b/tests/ui/thir-print/thir-flat.rs
new file mode 100644 (file)
index 0000000..8fa95ce
--- /dev/null
@@ -0,0 +1,4 @@
+// compile-flags: -Z unpretty=thir-flat
+// check-pass
+
+pub fn main() {}
diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout
new file mode 100644 (file)
index 0000000..c399fa6
--- /dev/null
@@ -0,0 +1,56 @@
+DefId(0:3 ~ thir_flat[45a6]::main):
+Thir {
+    arms: [],
+    blocks: [
+        Block {
+            targeted_by_break: false,
+            region_scope: Node(1),
+            opt_destruction_scope: None,
+            span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
+            stmts: [],
+            expr: None,
+            safety_mode: Safe,
+        },
+    ],
+    exprs: [
+        Expr {
+            ty: (),
+            temp_lifetime: Some(
+                Node(2),
+            ),
+            span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
+            kind: Block {
+                block: b0,
+            },
+        },
+        Expr {
+            ty: (),
+            temp_lifetime: Some(
+                Node(2),
+            ),
+            span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
+            kind: Scope {
+                region_scope: Node(2),
+                lint_level: Explicit(
+                    HirId(DefId(0:3 ~ thir_flat[45a6]::main).2),
+                ),
+                value: e0,
+            },
+        },
+        Expr {
+            ty: (),
+            temp_lifetime: Some(
+                Node(2),
+            ),
+            span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
+            kind: Scope {
+                region_scope: Destruction(2),
+                lint_level: Inherited,
+                value: e1,
+            },
+        },
+    ],
+    stmts: [],
+    params: [],
+}
+
diff --git a/tests/ui/thir-print/thir-tree-match.rs b/tests/ui/thir-print/thir-tree-match.rs
new file mode 100644 (file)
index 0000000..a5511ec
--- /dev/null
@@ -0,0 +1,23 @@
+// check-pass
+// compile-flags: -Zunpretty=thir-tree
+
+enum Bar {
+    First,
+    Second,
+    Third,
+}
+
+enum Foo {
+    FooOne(Bar),
+    FooTwo,
+}
+
+fn has_match(foo: Foo) -> bool {
+    match foo {
+        Foo::FooOne(Bar::First) => true,
+        Foo::FooOne(_) => false,
+        Foo::FooTwo => true,
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
new file mode 100644 (file)
index 0000000..d6174ec
--- /dev/null
@@ -0,0 +1,342 @@
+DefId(0:16 ~ thir_tree_match[3c9a]::has_match):
+params: [
+    Param {
+        ty: Foo
+        ty_span: Some($DIR/thir-tree-match.rs:15:19: 15:22 (#0))
+        self_kind: None
+        hir_id: Some(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).1))
+        param: Some( 
+            Pat: {
+                ty: Foo
+                span: $DIR/thir-tree-match.rs:15:14: 15:17 (#0)
+                kind: PatKind {
+                    Binding {
+                        mutability: Not
+                        name: "foo"
+                        mode: ByValue
+                        var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).2))
+                        ty: Foo
+                        is_primary: true
+                        subpattern: None
+                    }
+                }
+            }
+        )
+    }
+]
+body:
+    Expr {
+        ty: bool
+        temp_lifetime: Some(Node(26))
+        span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
+        kind: 
+            Scope {
+                region_scope: Destruction(26)
+                lint_level: Inherited
+                value:
+                    Expr {
+                        ty: bool
+                        temp_lifetime: Some(Node(26))
+                        span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
+                        kind: 
+                            Scope {
+                                region_scope: Node(26)
+                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).26))
+                                value:
+                                    Expr {
+                                        ty: bool
+                                        temp_lifetime: Some(Node(26))
+                                        span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
+                                        kind: 
+                                            Block {
+                                                targeted_by_break: false
+                                                opt_destruction_scope: None
+                                                span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
+                                                region_scope: Node(25)
+                                                safety_mode: Safe
+                                                stmts: []
+                                                expr:
+                                                    Expr {
+                                                        ty: bool
+                                                        temp_lifetime: Some(Node(26))
+                                                        span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
+                                                        kind: 
+                                                            Scope {
+                                                                region_scope: Node(3)
+                                                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).3))
+                                                                value:
+                                                                    Expr {
+                                                                        ty: bool
+                                                                        temp_lifetime: Some(Node(26))
+                                                                        span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
+                                                                        kind: 
+                                                                            Match {
+                                                                                scrutinee:
+                                                                                    Expr {
+                                                                                        ty: Foo
+                                                                                        temp_lifetime: Some(Node(26))
+                                                                                        span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
+                                                                                        kind: 
+                                                                                            Scope {
+                                                                                                region_scope: Node(4)
+                                                                                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).4))
+                                                                                                value:
+                                                                                                    Expr {
+                                                                                                        ty: Foo
+                                                                                                        temp_lifetime: Some(Node(26))
+                                                                                                        span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
+                                                                                                        kind: 
+                                                                                                            VarRef {
+                                                                                                                id: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).2))
+                                                                                                            }
+                                                                                                    }
+                                                                                            }
+                                                                                    }
+                                                                                arms: [
+                                                                                    Arm {
+                                                                                        pattern: 
+                                                                                            Pat: {
+                                                                                                ty: Foo
+                                                                                                span: $DIR/thir-tree-match.rs:17:9: 17:32 (#0)
+                                                                                                kind: PatKind {
+                                                                                                    Variant {
+                                                                                                        adt_def: 
+                                                                                                            AdtDef {
+                                                                                                                did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo)
+                                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }]
+                                                                                                                flags: IS_ENUM
+                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 }
+                                                                                                        substs: []
+                                                                                                        variant_index: 0
+                                                                                                        subpatterns: [
+                                                                                                            Pat: {
+                                                                                                                ty: Bar
+                                                                                                                span: $DIR/thir-tree-match.rs:17:21: 17:31 (#0)
+                                                                                                                kind: PatKind {
+                                                                                                                    Variant {
+                                                                                                                        adt_def: 
+                                                                                                                            AdtDef {
+                                                                                                                                did: DefId(0:3 ~ thir_tree_match[3c9a]::Bar)
+                                                                                                                                variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[3c9a]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[3c9a]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[3c9a]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[3c9a]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[3c9a]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[3c9a]::Bar::Third::{constructor#0}))), name: "Third", discr: Relative(2), fields: [], flags: NO_VARIANT_FLAGS }]
+                                                                                                                                flags: IS_ENUM
+                                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 3125160937860410723 }
+                                                                                                                        substs: []
+                                                                                                                        variant_index: 0
+                                                                                                                        subpatterns: []
+                                                                                                                    }
+                                                                                                                }
+                                                                                                            }
+                                                                                                        ]
+                                                                                                    }
+                                                                                                }
+                                                                                            }
+                                                                                        guard: None
+                                                                                        body: 
+                                                                                            Expr {
+                                                                                                ty: bool
+                                                                                                temp_lifetime: Some(Node(13))
+                                                                                                span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
+                                                                                                kind: 
+                                                                                                    Scope {
+                                                                                                        region_scope: Destruction(13)
+                                                                                                        lint_level: Inherited
+                                                                                                        value:
+                                                                                                            Expr {
+                                                                                                                ty: bool
+                                                                                                                temp_lifetime: Some(Node(13))
+                                                                                                                span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
+                                                                                                                kind: 
+                                                                                                                    Scope {
+                                                                                                                        region_scope: Node(13)
+                                                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).13))
+                                                                                                                        value:
+                                                                                                                            Expr {
+                                                                                                                                ty: bool
+                                                                                                                                temp_lifetime: Some(Node(13))
+                                                                                                                                span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
+                                                                                                                                kind: 
+                                                                                                                                    Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false)
+
+                                                                                                                            }
+                                                                                                                    }
+                                                                                                            }
+                                                                                                    }
+                                                                                            }
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).12))
+                                                                                        scope: Node(12)
+                                                                                        span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0)
+                                                                                    }
+                                                                                    Arm {
+                                                                                        pattern: 
+                                                                                            Pat: {
+                                                                                                ty: Foo
+                                                                                                span: $DIR/thir-tree-match.rs:18:9: 18:23 (#0)
+                                                                                                kind: PatKind {
+                                                                                                    Variant {
+                                                                                                        adt_def: 
+                                                                                                            AdtDef {
+                                                                                                                did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo)
+                                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }]
+                                                                                                                flags: IS_ENUM
+                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 }
+                                                                                                        substs: []
+                                                                                                        variant_index: 0
+                                                                                                        subpatterns: [
+                                                                                                            Pat: {
+                                                                                                                ty: Bar
+                                                                                                                span: $DIR/thir-tree-match.rs:18:21: 18:22 (#0)
+                                                                                                                kind: PatKind {
+                                                                                                                    Wild
+                                                                                                                }
+                                                                                                            }
+                                                                                                        ]
+                                                                                                    }
+                                                                                                }
+                                                                                            }
+                                                                                        guard: None
+                                                                                        body: 
+                                                                                            Expr {
+                                                                                                ty: bool
+                                                                                                temp_lifetime: Some(Node(19))
+                                                                                                span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
+                                                                                                kind: 
+                                                                                                    Scope {
+                                                                                                        region_scope: Destruction(19)
+                                                                                                        lint_level: Inherited
+                                                                                                        value:
+                                                                                                            Expr {
+                                                                                                                ty: bool
+                                                                                                                temp_lifetime: Some(Node(19))
+                                                                                                                span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
+                                                                                                                kind: 
+                                                                                                                    Scope {
+                                                                                                                        region_scope: Node(19)
+                                                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).19))
+                                                                                                                        value:
+                                                                                                                            Expr {
+                                                                                                                                ty: bool
+                                                                                                                                temp_lifetime: Some(Node(19))
+                                                                                                                                span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
+                                                                                                                                kind: 
+                                                                                                                                    Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false)
+
+                                                                                                                            }
+                                                                                                                    }
+                                                                                                            }
+                                                                                                    }
+                                                                                            }
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).18))
+                                                                                        scope: Node(18)
+                                                                                        span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0)
+                                                                                    }
+                                                                                    Arm {
+                                                                                        pattern: 
+                                                                                            Pat: {
+                                                                                                ty: Foo
+                                                                                                span: $DIR/thir-tree-match.rs:19:9: 19:20 (#0)
+                                                                                                kind: PatKind {
+                                                                                                    Variant {
+                                                                                                        adt_def: 
+                                                                                                            AdtDef {
+                                                                                                                did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo)
+                                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }]
+                                                                                                                flags: IS_ENUM
+                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 }
+                                                                                                        substs: []
+                                                                                                        variant_index: 1
+                                                                                                        subpatterns: []
+                                                                                                    }
+                                                                                                }
+                                                                                            }
+                                                                                        guard: None
+                                                                                        body: 
+                                                                                            Expr {
+                                                                                                ty: bool
+                                                                                                temp_lifetime: Some(Node(24))
+                                                                                                span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
+                                                                                                kind: 
+                                                                                                    Scope {
+                                                                                                        region_scope: Destruction(24)
+                                                                                                        lint_level: Inherited
+                                                                                                        value:
+                                                                                                            Expr {
+                                                                                                                ty: bool
+                                                                                                                temp_lifetime: Some(Node(24))
+                                                                                                                span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
+                                                                                                                kind: 
+                                                                                                                    Scope {
+                                                                                                                        region_scope: Node(24)
+                                                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).24))
+                                                                                                                        value:
+                                                                                                                            Expr {
+                                                                                                                                ty: bool
+                                                                                                                                temp_lifetime: Some(Node(24))
+                                                                                                                                span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
+                                                                                                                                kind: 
+                                                                                                                                    Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)
+
+                                                                                                                            }
+                                                                                                                    }
+                                                                                                            }
+                                                                                                    }
+                                                                                            }
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).23))
+                                                                                        scope: Node(23)
+                                                                                        span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0)
+                                                                                    }
+                                                                                ]
+                                                                            }
+                                                                    }
+                                                            }
+                                                    }
+                                            }
+                                    }
+                            }
+                    }
+            }
+    }
+
+
+DefId(0:17 ~ thir_tree_match[3c9a]::main):
+params: [
+]
+body:
+    Expr {
+        ty: ()
+        temp_lifetime: Some(Node(2))
+        span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
+        kind: 
+            Scope {
+                region_scope: Destruction(2)
+                lint_level: Inherited
+                value:
+                    Expr {
+                        ty: ()
+                        temp_lifetime: Some(Node(2))
+                        span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
+                        kind: 
+                            Scope {
+                                region_scope: Node(2)
+                                lint_level: Explicit(HirId(DefId(0:17 ~ thir_tree_match[3c9a]::main).2))
+                                value:
+                                    Expr {
+                                        ty: ()
+                                        temp_lifetime: Some(Node(2))
+                                        span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
+                                        kind: 
+                                            Block {
+                                                targeted_by_break: false
+                                                opt_destruction_scope: None
+                                                span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
+                                                region_scope: Node(1)
+                                                safety_mode: Safe
+                                                stmts: []
+                                                expr: []
+                                            }
+                                    }
+                            }
+                    }
+            }
+    }
+
+
diff --git a/tests/ui/thir-print/thir-tree.rs b/tests/ui/thir-print/thir-tree.rs
new file mode 100644 (file)
index 0000000..32df790
--- /dev/null
@@ -0,0 +1,4 @@
+// compile-flags: -Z unpretty=thir-tree
+// check-pass
+
+pub fn main() {}
diff --git a/tests/ui/thir-print/thir-tree.stdout b/tests/ui/thir-print/thir-tree.stdout
new file mode 100644 (file)
index 0000000..0a35d9f
--- /dev/null
@@ -0,0 +1,43 @@
+DefId(0:3 ~ thir_tree[8f1d]::main):
+params: [
+]
+body:
+    Expr {
+        ty: ()
+        temp_lifetime: Some(Node(2))
+        span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
+        kind: 
+            Scope {
+                region_scope: Destruction(2)
+                lint_level: Inherited
+                value:
+                    Expr {
+                        ty: ()
+                        temp_lifetime: Some(Node(2))
+                        span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
+                        kind: 
+                            Scope {
+                                region_scope: Node(2)
+                                lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2))
+                                value:
+                                    Expr {
+                                        ty: ()
+                                        temp_lifetime: Some(Node(2))
+                                        span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
+                                        kind: 
+                                            Block {
+                                                targeted_by_break: false
+                                                opt_destruction_scope: None
+                                                span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
+                                                region_scope: Node(1)
+                                                safety_mode: Safe
+                                                stmts: []
+                                                expr: []
+                                            }
+                                    }
+                            }
+                    }
+            }
+    }
+
+
diff --git a/tests/ui/thir-tree.rs b/tests/ui/thir-tree.rs
deleted file mode 100644 (file)
index 32df790..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-// compile-flags: -Z unpretty=thir-tree
-// check-pass
-
-pub fn main() {}
diff --git a/tests/ui/thir-tree.stdout b/tests/ui/thir-tree.stdout
deleted file mode 100644 (file)
index 4b6915f..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-DefId(0:3 ~ thir_tree[8f1d]::main):
-Thir {
-    arms: [],
-    blocks: [
-        Block {
-            targeted_by_break: false,
-            region_scope: Node(1),
-            opt_destruction_scope: None,
-            span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
-            stmts: [],
-            expr: None,
-            safety_mode: Safe,
-        },
-    ],
-    exprs: [
-        Expr {
-            ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
-            span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
-            kind: Block {
-                block: b0,
-            },
-        },
-        Expr {
-            ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
-            span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
-            kind: Scope {
-                region_scope: Node(2),
-                lint_level: Explicit(
-                    HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2),
-                ),
-                value: e0,
-            },
-        },
-        Expr {
-            ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
-            span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
-            kind: Scope {
-                region_scope: Destruction(2),
-                lint_level: Inherited,
-                value: e1,
-            },
-        },
-    ],
-    stmts: [],
-    params: [],
-}
-
diff --git a/tests/ui/traits/alias/issue-60755.rs b/tests/ui/traits/alias/issue-60755.rs
new file mode 100644 (file)
index 0000000..6b955a7
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(trait_alias)]
+
+struct MyStruct {}
+trait MyFn = Fn(&MyStruct);
+
+fn foo(_: impl MyFn) {}
+
+fn main() {
+    foo(|_| {});
+}
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;
    |                        ^^^^^^^
    |                        |
index 68b95b42b3463f32261aeb309084473118464ed1..86c511c0895670325eede43ff595e3db6e964e50 100644 (file)
@@ -4,6 +4,16 @@ error[E0277]: the trait bound `T: TraitFoo` is not satisfied
 LL | impl<T> Copy for Foo<T> {}
    |                  ^^^^^^ the trait `TraitFoo` is not implemented for `T`
    |
+note: required for `Foo<T>` to implement `Clone`
+  --> $DIR/copy-impl-cannot-normalize.rs:12:9
+   |
+LL | impl<T> Clone for Foo<T>
+   |         ^^^^^     ^^^^^^
+LL | where
+LL |     T: TraitFoo,
+   |        -------- unsatisfied trait bound introduced here
+note: required by a bound in `Copy`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
 help: consider restricting type parameter `T`
    |
 LL | impl<T: TraitFoo> Copy for Foo<T> {}
diff --git a/tests/ui/traits/copy-is-not-modulo-regions.not_static.stderr b/tests/ui/traits/copy-is-not-modulo-regions.not_static.stderr
new file mode 100644 (file)
index 0000000..edd94d2
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0204]: the trait `Copy` may not be implemented for this type
+  --> $DIR/copy-is-not-modulo-regions.rs:13:21
+   |
+LL | struct Bar<'lt>(Foo<'lt>);
+   |                 -------- this field does not implement `Copy`
+...
+LL | impl<'any> Copy for Bar<'any> {}
+   |                     ^^^^^^^^^
+   |
+note: the `Copy` impl for `Foo<'any>` requires that `'any: 'static`
+  --> $DIR/copy-is-not-modulo-regions.rs:10:17
+   |
+LL | struct Bar<'lt>(Foo<'lt>);
+   |                 ^^^^^^^^
+help: consider restricting type parameter `'any`
+   |
+LL | impl<'any: 'static> Copy for Bar<'any> {}
+   |          +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0204`.
diff --git a/tests/ui/traits/copy-is-not-modulo-regions.rs b/tests/ui/traits/copy-is-not-modulo-regions.rs
new file mode 100644 (file)
index 0000000..adb8702
--- /dev/null
@@ -0,0 +1,19 @@
+// revisions: not_static yes_static
+//[yes_static] check-pass
+
+#[derive(Clone)]
+struct Foo<'lt>(&'lt ());
+
+impl Copy for Foo<'static> {}
+
+#[derive(Clone)]
+struct Bar<'lt>(Foo<'lt>);
+
+#[cfg(not_static)]
+impl<'any> Copy for Bar<'any> {}
+//[not_static]~^ the trait `Copy` may not be implemented for this type
+
+#[cfg(yes_static)]
+impl<'any> Copy for Bar<'static> {}
+
+fn main() {}
diff --git a/tests/ui/traits/copy-requires-self-wf.rs b/tests/ui/traits/copy-requires-self-wf.rs
new file mode 100644 (file)
index 0000000..9abfdfa
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+
+#[derive(Clone)]
+struct A<'a, T>(&'a T);
+
+impl<'a, T: Copy + 'a> Copy for A<'a, T> {}
+
+#[derive(Clone)]
+struct B<'a, T>(A<'a, T>);
+
+// `T: '_` should be implied by `WF(B<'_, T>)`.
+impl<T: Copy> Copy for B<'_, T> {}
+
+fn main() {}
diff --git a/tests/ui/traits/fn-trait-cast-diagnostic.rs b/tests/ui/traits/fn-trait-cast-diagnostic.rs
new file mode 100644 (file)
index 0000000..e20aa21
--- /dev/null
@@ -0,0 +1,26 @@
+// There are two different instances to check that even if
+// the trait is implemented for the output of a function,
+// it will still be displayed if the function itself implements a trait.
+trait Foo {}
+
+impl Foo for fn() -> bool {}
+impl Foo for bool {}
+
+fn example() -> bool {
+    true
+}
+
+trait NoOtherFoo {}
+
+impl NoOtherFoo for fn() -> bool {}
+
+fn do_on_foo(v: impl Foo) {}
+fn do_on_single_foo(v: impl NoOtherFoo) {}
+
+fn main() {
+    do_on_foo(example);
+    //~^ ERROR the trait bound
+
+    do_on_single_foo(example);
+    //~^ ERROR the trait bound
+}
diff --git a/tests/ui/traits/fn-trait-cast-diagnostic.stderr b/tests/ui/traits/fn-trait-cast-diagnostic.stderr
new file mode 100644 (file)
index 0000000..6851dcd
--- /dev/null
@@ -0,0 +1,43 @@
+error[E0277]: the trait bound `fn() -> bool {example}: Foo` is not satisfied
+  --> $DIR/fn-trait-cast-diagnostic.rs:21:15
+   |
+LL |     do_on_foo(example);
+   |     --------- ^^^^^^^ the trait `Foo` is not implemented for fn item `fn() -> bool {example}`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `do_on_foo`
+  --> $DIR/fn-trait-cast-diagnostic.rs:17:22
+   |
+LL | fn do_on_foo(v: impl Foo) {}
+   |                      ^^^ required by this bound in `do_on_foo`
+help: use parentheses to call this function
+   |
+LL |     do_on_foo(example());
+   |                      ++
+help: the trait `Foo` is implemented for fn pointer `fn() -> bool`, try casting using `as`
+   |
+LL |     do_on_foo(example as fn() -> bool);
+   |                       +++++++++++++++
+
+error[E0277]: the trait bound `fn() -> bool {example}: NoOtherFoo` is not satisfied
+  --> $DIR/fn-trait-cast-diagnostic.rs:24:22
+   |
+LL |     do_on_single_foo(example);
+   |     ---------------- ^^^^^^^ the trait `NoOtherFoo` is not implemented for fn item `fn() -> bool {example}`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `do_on_single_foo`
+  --> $DIR/fn-trait-cast-diagnostic.rs:18:29
+   |
+LL | fn do_on_single_foo(v: impl NoOtherFoo) {}
+   |                             ^^^^^^^^^^ required by this bound in `do_on_single_foo`
+help: the trait `NoOtherFoo` is implemented for fn pointer `fn() -> bool`, try casting using `as`
+   |
+LL |     do_on_single_foo(example as fn() -> bool);
+   |                              +++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/issue-106072.rs b/tests/ui/traits/issue-106072.rs
new file mode 100644 (file)
index 0000000..7064a39
--- /dev/null
@@ -0,0 +1,5 @@
+#[derive(Clone)] //~  trait objects must include the `dyn` keyword
+                 //~| trait objects must include the `dyn` keyword
+struct Foo;
+trait Foo {} //~ the name `Foo` is defined multiple times
+fn main() {}
diff --git a/tests/ui/traits/issue-106072.stderr b/tests/ui/traits/issue-106072.stderr
new file mode 100644 (file)
index 0000000..f9b7b81
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0428]: the name `Foo` is defined multiple times
+  --> $DIR/issue-106072.rs:4:1
+   |
+LL | struct Foo;
+   | ----------- previous definition of the type `Foo` here
+LL | trait Foo {}
+   | ^^^^^^^^^ `Foo` redefined here
+   |
+   = note: `Foo` must be defined only once in the type namespace of this module
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/issue-106072.rs:1:10
+   |
+LL | #[derive(Clone)]
+   |          ^^^^^
+   |
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/issue-106072.rs:1:10
+   |
+LL | #[derive(Clone)]
+   |          ^^^^^
+   |
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0428, E0782.
+For more information about an error, try `rustc --explain E0428`.
index 4fe12731475b493d8e9426b04cae17c35f95410e..6b5b721384cbbebb622b4cdaaee0b356c35e5e45 100644 (file)
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
 LL | impl<T> Complete for T {}
    |                      ^ the trait `Copy` is not implemented for `T`
    |
+note: required for `T` to implement `Partial`
+  --> $DIR/issue-43784-supertrait.rs:1:11
+   |
+LL | pub trait Partial: Copy {
+   |           ^^^^^^^
 note: required by a bound in `Complete`
   --> $DIR/issue-43784-supertrait.rs:4:21
    |
index 10597caf5b2dc09759e2a3430a26f592b7938e68..005939e0c46e4d39093d411cfaa3a832cdaa9545 100644 (file)
@@ -5,13 +5,11 @@
 //~| ERROR cannot find type `NotDefined` in this scope
 //~| ERROR cannot find type `N` in this scope
 //~| ERROR cannot find type `N` in this scope
-//~| ERROR `i32` is not an iterator
 
 #[derive(Clone, Copy)]
 //~^ ERROR the trait `Copy` may not be implemented for this type
 struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
 //~^ ERROR cannot find type `NotDefined` in this scope
 //~| ERROR cannot find type `N` in this scope
-//~| ERROR `i32` is not an iterator
 
 fn main() {}
index aa8384e98053969edf0601e4739900f1c7a843f4..5063fdca092731aeb154a9b66a55cff4b94006bb 100644 (file)
@@ -38,7 +38,7 @@ LL | struct Foo<NotDefined>(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, St
    |           ++++++++++++
 
 error[E0412]: cannot find type `N` in this scope
-  --> $DIR/issue-50480.rs:12:18
+  --> $DIR/issue-50480.rs:11:18
    |
 LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
    |            -     ^
@@ -55,20 +55,11 @@ LL | struct Bar<T, N>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, Strin
    |             +++
 
 error[E0412]: cannot find type `NotDefined` in this scope
-  --> $DIR/issue-50480.rs:12:21
+  --> $DIR/issue-50480.rs:11:21
    |
 LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
    |                     ^^^^^^^^^^ not found in this scope
 
-error[E0277]: `i32` is not an iterator
-  --> $DIR/issue-50480.rs:3:27
-   |
-LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
-   |
-   = help: the trait `Iterator` is not implemented for `i32`
-   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
-
 error[E0204]: the trait `Copy` may not be implemented for this type
   --> $DIR/issue-50480.rs:1:17
    |
@@ -82,17 +73,8 @@ LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
    |
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0277]: `i32` is not an iterator
-  --> $DIR/issue-50480.rs:12:33
-   |
-LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
-   |
-   = help: the trait `Iterator` is not implemented for `i32`
-   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
-
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/issue-50480.rs:10:17
+  --> $DIR/issue-50480.rs:9:17
    |
 LL | #[derive(Clone, Copy)]
    |                 ^^^^
@@ -104,7 +86,7 @@ LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
    |
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 10 previous errors
+error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0204, E0277, E0412.
+Some errors have detailed explanations: E0204, E0412.
 For more information about an error, try `rustc --explain E0204`.
index 7924d3db06f36efb7ce39b5e0740200fc312099e..a11867c03a689259dde89dd3adddef9e0822414f 100644 (file)
@@ -11,6 +11,13 @@ LL |         builder.push(output);
    |
    = note: expected type parameter `F`
                       found struct `Class<P>`
+help: the return type of this call is `Class<P>` due to the type of the argument passed
+  --> $DIR/issue-52893.rs:53:9
+   |
+LL |         builder.push(output);
+   |         ^^^^^^^^^^^^^------^
+   |                      |
+   |                      this argument influences the return type of `push`
 note: associated function defined here
   --> $DIR/issue-52893.rs:11:8
    |
index 3ff8f12f1b8ce8688378ef9ab7699d54a24edc24..fb6eebbd254a2034206d4829c6b1f44bc7f28c6b 100644 (file)
@@ -6,12 +6,15 @@ LL |     takes(function);
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
 note: required by a bound in `takes`
   --> $DIR/issue-99875.rs:9:18
    |
 LL | fn takes(_: impl Trait) {}
    |                  ^^^^^ required by this bound in `takes`
+help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`, try casting using `as`
+   |
+LL |     takes(function as fn(Argument) -> Return);
+   |                    +++++++++++++++++++++++++
 
 error[E0277]: the trait bound `[closure@$DIR/issue-99875.rs:14:11: 14:34]: Trait` is not satisfied
   --> $DIR/issue-99875.rs:14:11
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/fn-trait-closure.rs b/tests/ui/traits/new-solver/fn-trait-closure.rs
new file mode 100644 (file)
index 0000000..bd65737
--- /dev/null
@@ -0,0 +1,8 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+fn require_fn(_: impl Fn() -> i32) {}
+
+fn main() {
+    require_fn(|| -> i32 { 1i32 });
+}
diff --git a/tests/ui/traits/new-solver/fn-trait.rs b/tests/ui/traits/new-solver/fn-trait.rs
new file mode 100644 (file)
index 0000000..d566ead
--- /dev/null
@@ -0,0 +1,13 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+fn require_fn(_: impl Fn() -> i32) {}
+
+fn f() -> i32 {
+    1i32
+}
+
+fn main() {
+    require_fn(f);
+    require_fn(f as fn() -> i32);
+}
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() {}
diff --git a/tests/ui/traits/new-solver/pointer-sized.rs b/tests/ui/traits/new-solver/pointer-sized.rs
new file mode 100644 (file)
index 0000000..15681cd
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(pointer_sized_trait)]
+
+use std::marker::PointerSized;
+
+fn require_pointer_sized(_: impl PointerSized) {}
+
+fn main() {
+    require_pointer_sized(1usize);
+    require_pointer_sized(1u16);
+    //~^ ERROR `u16` needs to be a pointer-sized type
+    require_pointer_sized(&1i16);
+}
diff --git a/tests/ui/traits/new-solver/pointer-sized.stderr b/tests/ui/traits/new-solver/pointer-sized.stderr
new file mode 100644 (file)
index 0000000..b250b13
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0277]: `u16` needs to be a pointer-sized type
+  --> $DIR/pointer-sized.rs:9:27
+   |
+LL |     require_pointer_sized(1u16);
+   |     --------------------- ^^^^ the trait `PointerSized` is not implemented for `u16`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: the trait bound `u16: PointerSized` is not satisfied
+note: required by a bound in `require_pointer_sized`
+  --> $DIR/pointer-sized.rs:5:34
+   |
+LL | fn require_pointer_sized(_: impl PointerSized) {}
+   |                                  ^^^^^^^^^^^^ required by this bound in `require_pointer_sized`
+help: consider borrowing here
+   |
+LL |     require_pointer_sized(&1u16);
+   |                           +
+LL |     require_pointer_sized(&mut 1u16);
+   |                           ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/track-obligations.rs b/tests/ui/traits/track-obligations.rs
new file mode 100644 (file)
index 0000000..77e753c
--- /dev/null
@@ -0,0 +1,88 @@
+// These are simplifications of the tower traits by the same name:
+
+pub trait Service<Request> {
+    type Response;
+}
+
+pub trait Layer<C> {
+    type Service;
+}
+
+// Any type will do here:
+
+pub struct Req;
+pub struct Res;
+
+// This is encoding a trait alias.
+
+pub trait ParticularService:
+    Service<Req, Response = Res> {
+}
+
+impl<T> ParticularService for T
+where
+    T: Service<Req, Response = Res>,
+{
+}
+
+// This is also a trait alias.
+// The weird = <Self as ...> bound is there so that users of the trait do not
+// need to repeat the bounds. See https://github.com/rust-lang/rust/issues/20671
+// for context, and in particular the workaround in:
+// https://github.com/rust-lang/rust/issues/20671#issuecomment-529752828
+
+pub trait ParticularServiceLayer<C>:
+    Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
+{
+    type Service: ParticularService;
+}
+
+impl<T, C> ParticularServiceLayer<C> for T
+where
+    T: Layer<C>,
+    T::Service: ParticularService,
+{
+    type Service = T::Service;
+}
+
+// These are types that implement the traits that the trait aliases refer to.
+// They should also implement the alias traits due to the blanket impls.
+
+struct ALayer<C>(C);
+impl<C> Layer<C> for ALayer<C> {
+    type Service = AService;
+}
+
+struct AService;
+impl Service<Req> for AService {
+    // However, AService does _not_ meet the blanket implementation,
+    // since its Response type is bool, not Res as it should be.
+    type Response = bool;
+}
+
+// This is a wrapper type around ALayer that uses the trait alias
+// as a way to communicate the requirements of the provided types.
+struct Client<C>(C);
+
+// The method and the free-standing function below both have the same bounds.
+
+impl<C> Client<C>
+where
+    ALayer<C>: ParticularServiceLayer<C>,
+{
+    fn check(&self) {}
+}
+
+fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
+
+// But, they give very different error messages.
+
+fn main() {
+    // This gives a very poor error message that does nothing to point the user
+    // at the underlying cause of why the types involved do not meet the bounds.
+    Client(()).check(); //~ ERROR E0599
+
+    // This gives a good(ish) error message that points the user at _why_ the
+    // bound isn't met, and thus how they might fix it.
+    check(()); //~ ERROR E0271
+}
diff --git a/tests/ui/traits/track-obligations.stderr b/tests/ui/traits/track-obligations.stderr
new file mode 100644 (file)
index 0000000..8947747
--- /dev/null
@@ -0,0 +1,76 @@
+error[E0599]: the method `check` exists for struct `Client<()>`, but its trait bounds were not satisfied
+  --> $DIR/track-obligations.rs:83:16
+   |
+LL | struct ALayer<C>(C);
+   | ----------------
+   | |
+   | doesn't satisfy `<_ as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service`
+   | doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>`
+...
+LL | struct Client<C>(C);
+   | ---------------- method `check` not found for this struct
+...
+LL |     Client(()).check();
+   |                ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds
+   |
+note: trait bound `<ALayer<()> as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service` was not satisfied
+  --> $DIR/track-obligations.rs:35:14
+   |
+LL | pub trait ParticularServiceLayer<C>:
+   |           ----------------------
+LL |     Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
+note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied
+  --> $DIR/track-obligations.rs:71:16
+   |
+LL | impl<C> Client<C>
+   |         ---------
+LL | where
+LL |     ALayer<C>: ParticularServiceLayer<C>,
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
+note: the trait `ParticularServiceLayer` must be implemented
+  --> $DIR/track-obligations.rs:34:1
+   |
+LL | / pub trait ParticularServiceLayer<C>:
+LL | |     Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
+   | |____________________________________________________________________^
+
+error[E0271]: type mismatch resolving `<AService as Service<Req>>::Response == Res`
+  --> $DIR/track-obligations.rs:87:11
+   |
+LL |     check(());
+   |     ----- ^^ type mismatch resolving `<AService as Service<Req>>::Response == Res`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: expected this to be `Res`
+  --> $DIR/track-obligations.rs:60:21
+   |
+LL |     type Response = bool;
+   |                     ^^^^
+note: required for `AService` to implement `ParticularService`
+  --> $DIR/track-obligations.rs:22:9
+   |
+LL | impl<T> ParticularService for T
+   |         ^^^^^^^^^^^^^^^^^     ^
+LL | where
+LL |     T: Service<Req, Response = Res>,
+   |                     -------------- unsatisfied trait bound introduced here
+note: required for `ALayer<_>` to implement `ParticularServiceLayer<_>`
+  --> $DIR/track-obligations.rs:40:12
+   |
+LL | impl<T, C> ParticularServiceLayer<C> for T
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^     ^
+...
+LL |     T::Service: ParticularService,
+   |                 ----------------- unsatisfied trait bound introduced here
+note: required by a bound in `check`
+  --> $DIR/track-obligations.rs:76:36
+   |
+LL | fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0271, E0599.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs
new file mode 100644 (file)
index 0000000..3c6ab86
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(multiple_supertrait_upcastable)]
+#![deny(multiple_supertrait_upcastable)]
+
+trait A {}
+trait B {}
+
+trait C: A + B {}
+//~^ ERROR `C` is object-safe and has multiple supertraits
+
+fn main() {}
diff --git a/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr
new file mode 100644 (file)
index 0000000..ad80a00
--- /dev/null
@@ -0,0 +1,14 @@
+error: `C` is object-safe and has multiple supertraits
+  --> $DIR/multiple_supertrait_upcastable.rs:7:1
+   |
+LL | trait C: A + B {}
+   | ^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/multiple_supertrait_upcastable.rs:2:9
+   |
+LL | #![deny(multiple_supertrait_upcastable)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
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 4d2890b5de583c48bc63a8e6d727e4d3516f03f1..0bcc9e002ca0449040b54f47cade01bcc9e0b259 100644 (file)
@@ -14,5 +14,5 @@ impl<W> Trait<W> for () {}
 
 fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
     ()
-    //~^ ERROR non-defining opaque type use
+    //~^ ERROR expected generic type parameter, found `<T as TraitWithAssoc>::Assoc`
 }
index c405b1f6af2057428a78bf0dc88993d954d99ad7..3c259bd9e97cc08c2d3e04eaf57ac048d94924d9 100644 (file)
@@ -1,14 +1,12 @@
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic type parameter, found `<T as TraitWithAssoc>::Assoc`
   --> $DIR/bound_reduction2.rs:16:5
    |
+LL | type Foo<V> = impl Trait<V>;
+   |          - this generic parameter must be used with a generic type parameter
+...
 LL |     ()
    |     ^^
-   |
-note: used non-generic type `<T as TraitWithAssoc>::Assoc` for generic parameter
-  --> $DIR/bound_reduction2.rs:9:10
-   |
-LL | type Foo<V> = impl Trait<V>;
-   |          ^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0792`.
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 f39741a6a625cc2d693309227e45982ad3515156..e7b8567b9a217d7e629343116d52655ac114e04a 100644 (file)
@@ -10,20 +10,19 @@ fn main() {}
 
 type OneConst<const X: usize> = impl Debug;
 
-
 // Not defining uses, because they doesn't define *all* possible generics.
 
 fn concrete_ty() -> OneTy<u32> {
     5u32
-    //~^ ERROR non-defining opaque type use in defining scope
+    //~^ ERROR expected generic type parameter, found `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 }> {
     7u32
-    //~^ ERROR non-defining opaque type use in defining scope
+    //~^ ERROR expected generic constant parameter, found `123`
 }
index e7565525ad3387396ac5c7f9d2efd85ae366943f..966fe823f024dd99e4f3e6d1e70688ffb674aa97 100644 (file)
@@ -1,17 +1,14 @@
-error: non-defining opaque type use in defining scope
-  --> $DIR/generic_nondefining_use.rs:17:5
+error[E0792]: expected generic type parameter, found `u32`
+  --> $DIR/generic_nondefining_use.rs:16:5
    |
+LL | type OneTy<T> = impl Debug;
+   |            - this generic parameter must be used with a generic type parameter
+...
 LL |     5u32
    |     ^^^^
-   |
-note: used non-generic type `u32` for generic parameter
-  --> $DIR/generic_nondefining_use.rs:7:12
-   |
-LL | type OneTy<T> = impl Debug;
-   |            ^
 
-error: non-defining opaque type use in defining scope
-  --> $DIR/generic_nondefining_use.rs:22:5
+error[E0792]: expected generic lifetime parameter, found `'static`
+  --> $DIR/generic_nondefining_use.rs:21:5
    |
 LL | type OneLifetime<'a> = impl Debug;
    |                  -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
@@ -19,17 +16,15 @@ LL | type OneLifetime<'a> = impl Debug;
 LL |     6u32
    |     ^^^^
 
-error: non-defining opaque type use in defining scope
-  --> $DIR/generic_nondefining_use.rs:27:5
+error[E0792]: expected generic constant parameter, found `123`
+  --> $DIR/generic_nondefining_use.rs:26:5
    |
+LL | type OneConst<const X: usize> = impl Debug;
+   |               -------------- this generic parameter must be used with a generic constant parameter
+...
 LL |     7u32
    |     ^^^^
-   |
-note: used non-generic constant `123` for generic parameter
-  --> $DIR/generic_nondefining_use.rs:11:15
-   |
-LL | type OneConst<const X: usize> = impl Debug;
-   |               ^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0792`.
index cb90776472b5dc543fd395548d0cbe41082ca61f..d3e169a70d3f7f30471d26e9186092e2a83ad880 100644 (file)
@@ -4,7 +4,7 @@ fn main() {
     let y = 42;
     let x = wrong_generic(&y);
     let z: i32 = x;
-    //~^ ERROR non-defining opaque type use
+    //~^ ERROR expected generic type parameter, found `&'static i32
 }
 
 type WrongGeneric<T> = impl 'static;
index ba583241a696b57dc23c5ac20908c54d29abfb29..19115fd28662be97e91c77088a4f7b2cb5c299a4 100644 (file)
@@ -4,17 +4,14 @@ error: at least one trait must be specified
 LL | type WrongGeneric<T> = impl 'static;
    |                        ^^^^^^^^^^^^
 
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic type parameter, found `&'static i32`
   --> $DIR/generic_type_does_not_live_long_enough.rs:6:18
    |
 LL |     let z: i32 = x;
    |                  ^
-   |
-note: used non-generic type `&'static i32` for generic parameter
-  --> $DIR/generic_type_does_not_live_long_enough.rs:10:19
-   |
+...
 LL | type WrongGeneric<T> = impl 'static;
-   |                   ^
+   |                   - this generic parameter must be used with a generic type parameter
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/generic_type_does_not_live_long_enough.rs:14:5
@@ -29,4 +26,5 @@ LL | fn wrong_generic<T: 'static>(t: T) -> WrongGeneric<T> {
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0310`.
+Some errors have detailed explanations: E0310, E0792.
+For more information about an error, try `rustc --explain E0310`.
diff --git a/tests/ui/type-alias-impl-trait/issue-104817.rs b/tests/ui/type-alias-impl-trait/issue-104817.rs
new file mode 100644 (file)
index 0000000..0d3bace
--- /dev/null
@@ -0,0 +1,19 @@
+#![feature(type_alias_impl_trait)]
+#![cfg_attr(specialized, feature(specialization))]
+#![allow(incomplete_features)]
+
+// revisions: stock specialized
+// [specialized]check-pass
+
+trait OpaqueTrait {}
+impl<T> OpaqueTrait for T {}
+type OpaqueType = impl OpaqueTrait;
+fn mk_opaque() -> OpaqueType {
+    || 0
+}
+trait AnotherTrait {}
+impl<T: Send> AnotherTrait for T {}
+impl AnotherTrait for OpaqueType {}
+//[stock]~^ conflicting implementations of trait `AnotherTrait` for type `OpaqueType`
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/issue-104817.stock.stderr b/tests/ui/type-alias-impl-trait/issue-104817.stock.stderr
new file mode 100644 (file)
index 0000000..47bae8b
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0119]: conflicting implementations of trait `AnotherTrait` for type `OpaqueType`
+  --> $DIR/issue-104817.rs:16:1
+   |
+LL | impl<T: Send> AnotherTrait for T {}
+   | -------------------------------- first implementation here
+LL | impl AnotherTrait for OpaqueType {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `OpaqueType`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
index 438ac35fdea515276a4d7bfb41028aa21fd9ea21..057930f0c1ce759a4d12c4ebff64c43076ab3714 100644 (file)
@@ -4,7 +4,6 @@
 type Bug<T, U> = impl Fn(T) -> U + Copy; //~ ERROR cycle detected
 
 const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
-//~^ ERROR: cannot transmute
 
 fn make_bug<T, U: From<T>>() -> Bug<T, U> {
     |x| x.into() //~ ERROR the trait bound `U: From<T>` is not satisfied
index 1b89d55711dbd690c37f78b37af5a46e868d4cdc..2565a28b493541c1a48bc195e01546d1dfe66160 100644 (file)
@@ -24,23 +24,14 @@ LL | |     CONST_BUG(0);
 LL | | }
    | |_^
 
-error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
-  --> $DIR/issue-53092-2.rs:6:41
-   |
-LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
-   |                                         ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: source type: `[closure@$DIR/issue-53092-2.rs:6:61: 6:68]` (0 bits)
-   = note: target type: `Bug<u8, ()>` (size can vary because of [type error])
-
 error[E0277]: the trait bound `U: From<T>` is not satisfied
-  --> $DIR/issue-53092-2.rs:10:5
+  --> $DIR/issue-53092-2.rs:9:5
    |
 LL |     |x| x.into()
    |     ^^^^^^^^^^^^ the trait `From<T>` is not implemented for `U`
    |
 note: required by a bound in `make_bug`
-  --> $DIR/issue-53092-2.rs:9:19
+  --> $DIR/issue-53092-2.rs:8:19
    |
 LL | fn make_bug<T, U: From<T>>() -> Bug<T, U> {
    |                   ^^^^^^^ required by this bound in `make_bug`
@@ -49,7 +40,7 @@ help: consider restricting type parameter `U`
 LL | type Bug<T, U: std::convert::From<T>> = impl Fn(T) -> U + Copy;
    |              +++++++++++++++++++++++
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0277, E0391, E0512.
+Some errors have detailed explanations: E0277, E0391.
 For more information about an error, try `rustc --explain E0277`.
index 4fc7679311a2e55b031dd0cf0c460c979476212b..c2f4c37080746f3ef2437046074e3434ecbc38e4 100644 (file)
@@ -18,7 +18,7 @@ impl<T: Copy, E> IterBits for T
     type BitsIter = IterBitsIter<T, E, u8>;
     fn iter_bits(self, n: u8) -> Self::BitsIter {
         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
-        //~^ ERROR non-defining opaque type use in defining scope
+        //~^ ERROR expected generic type parameter, found `u8`
     }
 }
 
index bbc93657be32f27501c851460adbfb0554ee0826..f8fdb004d098996e1af34800fe48011c533c341f 100644 (file)
@@ -1,14 +1,12 @@
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic type parameter, found `u8`
   --> $DIR/issue-60564.rs:20:9
    |
+LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
+   |                         - this generic parameter must be used with a generic type parameter
+...
 LL |         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: used non-generic type `u8` for generic parameter
-  --> $DIR/issue-60564.rs:8:25
-   |
-LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
-   |                         ^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0792`.
index 5223fb1c702d6753c92e6f6ac2e9938732faf792..5e0a82a72868ab88337ba20251768de6c23193b3 100644 (file)
@@ -7,7 +7,7 @@ trait Trait<T> {}
 type Alias<'a, U> = impl Trait<U>;
 
 fn f<'a>() -> Alias<'a, ()> {}
-//~^ ERROR non-defining opaque type use in defining scope
+//~^ ERROR expected generic type parameter, found `()`
 
 fn main() {}
 
index 7fb9a0c410e83c8c976a78979f913279f462b84e..271743a4010c8faa841a82027d8520e96a019546 100644 (file)
@@ -1,14 +1,12 @@
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic type parameter, found `()`
   --> $DIR/issue-68368-non-defining-use-2.rs:9:29
    |
+LL | type Alias<'a, U> = impl Trait<U>;
+   |                - this generic parameter must be used with a generic type parameter
+LL |
 LL | fn f<'a>() -> Alias<'a, ()> {}
    |                             ^^
-   |
-note: used non-generic type `()` for generic parameter
-  --> $DIR/issue-68368-non-defining-use-2.rs:7:16
-   |
-LL | type Alias<'a, U> = impl Trait<U>;
-   |                ^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0792`.
index b50462bf237bb9509f9d090097ef9675af48b8b8..3b32260c96fe14b9a84821de686d21de5aec353c 100644 (file)
@@ -7,7 +7,7 @@ trait Trait<T> {}
 type Alias<'a, U> = impl Trait<U>;
 
 fn f<'a>() -> Alias<'a, ()> {}
-//~^ ERROR non-defining opaque type use in defining scope
+//~^ ERROR expected generic type parameter, found `()`
 
 fn main() {}
 
index 8059621b61a096bc84ed17714d7130d44e864d72..4d9a8d6eef9156bbda6c22542093104cd88c504f 100644 (file)
@@ -1,14 +1,12 @@
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic type parameter, found `()`
   --> $DIR/issue-68368-non-defining-use.rs:9:29
    |
+LL | type Alias<'a, U> = impl Trait<U>;
+   |                - this generic parameter must be used with a generic type parameter
+LL |
 LL | fn f<'a>() -> Alias<'a, ()> {}
    |                             ^^
-   |
-note: used non-generic type `()` for generic parameter
-  --> $DIR/issue-68368-non-defining-use.rs:7:16
-   |
-LL | type Alias<'a, U> = impl Trait<U>;
-   |                ^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0792`.
index 428454bc04844d836b75c3a7fbde6796a1e84b53..7657fe2fb1aee34c86e37a4aa96905f7bb3c3a80 100644 (file)
@@ -18,6 +18,6 @@ impl<T> WithAssoc<T> for () {
 //~^ ERROR use of undeclared lifetime name `'a`
 
 fn my_fun() -> Return<()> {}
-//~^ ERROR non-defining opaque type use in defining scope
+//~^ ERROR expected generic type parameter, found `()`
 
 fn main() {}
index 7b50c8af26e5fe98d74a704b12ff57060e2f612b..d1250786d938c367c5cb2be6ab0ad6a5b693ee45 100644 (file)
@@ -14,18 +14,16 @@ help: consider introducing lifetime `'a` here
 LL | type Return<'a, A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
    |             +++
 
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic type parameter, found `()`
   --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27
    |
+LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+   |             - this generic parameter must be used with a generic type parameter
+...
 LL | fn my_fun() -> Return<()> {}
    |                           ^^
-   |
-note: used non-generic type `()` for generic parameter
-  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13
-   |
-LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
-   |             ^
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0261`.
+Some errors have detailed explanations: E0261, E0792.
+For more information about an error, try `rustc --explain E0261`.
index 46621362e4f73a2bc56837348fa7cf133a639fd1..0f0a02e97d82db4054e6531932337b7c3b939a3a 100644 (file)
@@ -15,5 +15,4 @@ pub fn bar(x: Foo) -> Foo {
 
 fn main() {
     let _: foo::Foo = std::mem::transmute(0u8);
-    //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
 }
index 337708b876524920b548aac95dfca8ffb6d0845f..f3e8ae9c7dbae9ff379197ee592b8de713090669 100644 (file)
@@ -6,15 +6,5 @@ LL |     pub type Foo = impl Copy;
    |
    = note: `Foo` must be used in combination with a concrete type within the same module
 
-error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
-  --> $DIR/no_inferrable_concrete_type.rs:17:23
-   |
-LL |     let _: foo::Foo = std::mem::transmute(0u8);
-   |                       ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: source type: `u8` (8 bits)
-   = note: target type: `Foo` (size can vary because of [type error])
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0512`.
diff --git a/tests/ui/type-alias-impl-trait/outlives-bound-var.rs b/tests/ui/type-alias-impl-trait/outlives-bound-var.rs
new file mode 100644 (file)
index 0000000..b8fac45
--- /dev/null
@@ -0,0 +1,18 @@
+// Here we process outlive obligations involving
+// opaque types with bound vars in substs.
+// This was an ICE.
+//
+// check-pass
+#![feature(type_alias_impl_trait)]
+
+type Ty<'a> = impl Sized + 'a;
+fn define<'a>() -> Ty<'a> {}
+
+// Ty<'^0>: 'static
+fn test1(_: &'static fn(Ty<'_>)) {}
+
+fn test2() {
+    None::<&fn(Ty<'_>)>;
+}
+
+fn main() { }
index be60cda68b9f0fb0ce1951d6d84934f929f10a1d..e544b369515489ba17258e2eac2ea7eb50575cb5 100644 (file)
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `(Vec<T>,)`
   --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:9
    |
 LL |     let (x, ) = (vec![], );
-   |         ^^^^^
+   |         ^^^^^   ---------- type must be known at this point
    |
 help: consider giving this pattern a type, where the type for type parameter `T` is specified
    |
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/type/wrong-call-return-type-due-to-generic-arg.rs b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs
new file mode 100644 (file)
index 0000000..ba5b9f5
--- /dev/null
@@ -0,0 +1,28 @@
+fn function<T>(x: T, y: bool) -> T {
+    x
+}
+
+struct S {}
+impl S {
+    fn method<T>(&self, x: T) -> T {
+        x
+    }
+}
+
+fn wrong_arg_type(x: u32) -> u32 {
+    x
+}
+
+fn main() {
+    // Should not trigger.
+    let x = wrong_arg_type(0u16); //~ ERROR mismatched types
+    let x: u16 = function(0, 0u8); //~ ERROR mismatched types
+
+    // Should trigger exactly once for the first argument.
+    let x: u16 = function(0u32, 0u8); //~ ERROR arguments to this function are incorrect
+
+    // Should trigger.
+    let x: u16 = function(0u32, true); //~ ERROR mismatched types
+    let x: u16 = (S {}).method(0u32); //~ ERROR mismatched types
+    function(0u32, 8u8) //~ ERROR arguments to this function are incorrect
+}
diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr
new file mode 100644 (file)
index 0000000..4d012cb
--- /dev/null
@@ -0,0 +1,131 @@
+error[E0308]: mismatched types
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:18:28
+   |
+LL |     let x = wrong_arg_type(0u16);
+   |             -------------- ^^^^ expected `u32`, found `u16`
+   |             |
+   |             arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:12:4
+   |
+LL | fn wrong_arg_type(x: u32) -> u32 {
+   |    ^^^^^^^^^^^^^^ ------
+help: change the type of the numeric literal from `u16` to `u32`
+   |
+LL |     let x = wrong_arg_type(0u32);
+   |                             ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:19:30
+   |
+LL |     let x: u16 = function(0, 0u8);
+   |                  --------    ^^^ expected `bool`, found `u8`
+   |                  |
+   |                  arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+   |
+LL | fn function<T>(x: T, y: bool) -> T {
+   |    ^^^^^^^^          -------
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:22:18
+   |
+LL |     let x: u16 = function(0u32, 0u8);
+   |                  ^^^^^^^^ ----  --- expected `bool`, found `u8`
+   |                           |
+   |                           expected `u16`, found `u32`
+   |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:22:18
+   |
+LL |     let x: u16 = function(0u32, 0u8);
+   |                  ^^^^^^^^^----^^^^^^
+   |                           |
+   |                           this argument influences the return type of `function`
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+   |
+LL | fn function<T>(x: T, y: bool) -> T {
+   |    ^^^^^^^^    ----  -------
+help: change the type of the numeric literal from `u32` to `u16`
+   |
+LL |     let x: u16 = function(0u16, 0u8);
+   |                            ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:25:27
+   |
+LL |     let x: u16 = function(0u32, true);
+   |                  -------- ^^^^ expected `u16`, found `u32`
+   |                  |
+   |                  arguments to this function are incorrect
+   |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:25:18
+   |
+LL |     let x: u16 = function(0u32, true);
+   |                  ^^^^^^^^^----^^^^^^^
+   |                           |
+   |                           this argument influences the return type of `function`
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+   |
+LL | fn function<T>(x: T, y: bool) -> T {
+   |    ^^^^^^^^    ----
+help: change the type of the numeric literal from `u32` to `u16`
+   |
+LL |     let x: u16 = function(0u16, true);
+   |                            ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:26:32
+   |
+LL |     let x: u16 = (S {}).method(0u32);
+   |                         ------ ^^^^ expected `u16`, found `u32`
+   |                         |
+   |                         arguments to this method are incorrect
+   |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:26:18
+   |
+LL |     let x: u16 = (S {}).method(0u32);
+   |                  ^^^^^^^^^^^^^^----^
+   |                                |
+   |                                this argument influences the return type of `method`
+note: associated function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:7:8
+   |
+LL |     fn method<T>(&self, x: T) -> T {
+   |        ^^^^^^           ----
+help: change the type of the numeric literal from `u32` to `u16`
+   |
+LL |     let x: u16 = (S {}).method(0u16);
+   |                                 ~~~
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5
+   |
+LL |     function(0u32, 8u8)
+   |     ^^^^^^^^ ----  --- expected `bool`, found `u8`
+   |              |
+   |              expected `()`, found `u32`
+   |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5
+   |
+LL |     function(0u32, 8u8)
+   |     ^^^^^^^^^----^^^^^^
+   |              |
+   |              this argument influences the return type of `function`
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+   |
+LL | fn function<T>(x: T, y: bool) -> T {
+   |    ^^^^^^^^    ----  -------
+
+error: aborting due to 6 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 5561673f3c6728e6bba507c3fd1305e82d85b498..42cfe38aed888e0b8dd69e61f44a5f03c670c1ce 100644 (file)
@@ -3,11 +3,6 @@ error[E0405]: cannot find trait `Oops` in this scope
    |
 LL |     let _: S<impl Oops> = S;
    |                   ^^^^ not found in this scope
-   |
-help: you might be missing a type parameter
-   |
-LL | fn f<Oops>() {
-   |     ++++++
 
 error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
   --> $DIR/issue-104513-ice.rs:3:14
diff --git a/tests/ui/typeck/issue-107087.rs b/tests/ui/typeck/issue-107087.rs
new file mode 100644 (file)
index 0000000..135cdf1
--- /dev/null
@@ -0,0 +1,18 @@
+struct A<T>(T);
+
+trait Foo {
+    type B;
+}
+
+impl Foo for A<u32> {
+    type B = i32;
+}
+
+impl Foo for A<i32> {
+    type B = i32;
+}
+
+fn main() {
+    A::B::<>::C
+    //~^ ERROR ambiguous associated type
+}
diff --git a/tests/ui/typeck/issue-107087.stderr b/tests/ui/typeck/issue-107087.stderr
new file mode 100644 (file)
index 0000000..70f1932
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0223]: ambiguous associated type
+  --> $DIR/issue-107087.rs:16:5
+   |
+LL |     A::B::<>::C
+   |     ^^^^^^^^ help: use the fully-qualified path: `<A<_> as Foo>::B`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0223`.
index f488463ae3ce9faedbd67b008ae8cac5468b11bd..8f5ff51fbe1007cb7e77aa405625b059df75ed5f 100644 (file)
@@ -8,6 +8,13 @@ LL | fn main() { test(Ok(())); }
    |
    = note:   expected enum `Option<()>`
            found unit type `()`
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-46112.rs:9:18
+   |
+LL | fn main() { test(Ok(())); }
+   |                  ^^^--^
+   |                     |
+   |                     this argument influences the type of `Ok`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
 help: try wrapping the expression in `Some`
index 00d23389720b9d636cd2272e0686d5361dd2bdbe..09f3aee2d9ec56a51a33b9639863e6950adba45e 100644 (file)
@@ -14,6 +14,13 @@ LL |     <F as FnOnce(&mut u8)>::call_once(f, 1)
    |
    = note: expected tuple `(&mut u8,)`
                found type `{integer}`
+help: the return type of this call is `{integer}` due to the type of the argument passed
+  --> $DIR/issue-84768.rs:7:5
+   |
+LL |     <F as FnOnce(&mut u8)>::call_once(f, 1)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^
+   |                                          |
+   |                                          this argument influences the return type of `FnOnce`
 note: associated function defined here
   --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
index 8508f7a38e2399b054d079b300ad17b11bf5ffff..78f392c9a8acc87913e01acb5c4dcbdf067391f6 100644 (file)
@@ -2,8 +2,9 @@ error: this file contains an unclosed delimiter
   --> $DIR/issue-91334.rs:10:23
    |
 LL | fn f(){||yield(((){),
-   |       -       -       ^
-   |       |       |
+   |       -       -    -  ^
+   |       |       |    |
+   |       |       |    missing open `(` for this delimiter
    |       |       unclosed delimiter
    |       unclosed delimiter
 
@@ -11,8 +12,9 @@ error: this file contains an unclosed delimiter
   --> $DIR/issue-91334.rs:10:23
    |
 LL | fn f(){||yield(((){),
-   |       -       -       ^
-   |       |       |
+   |       -       -    -  ^
+   |       |       |    |
+   |       |       |    missing open `(` for this delimiter
    |       |       unclosed delimiter
    |       unclosed delimiter
 
index a2fe627868aeb36faef45712e678d61e0e83064f..e85144a31ca96c8ebc87ebd1a178f889dd5528b5 100644 (file)
@@ -21,6 +21,13 @@ LL |     <i32 as Add<i32>>::add(1u32, 2);
    |     |
    |     arguments to this function are incorrect
    |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/ufcs-qpath-self-mismatch.rs:7:5
+   |
+LL |     <i32 as Add<i32>>::add(1u32, 2);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^----^^^^
+   |                            |
+   |                            this argument influences the return type of `Add`
 note: associated function defined here
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: change the type of the numeric literal from `u32` to `i32`
@@ -36,6 +43,13 @@ LL |     <i32 as Add<i32>>::add(1, 2u32);
    |     |
    |     arguments to this function are incorrect
    |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/ufcs-qpath-self-mismatch.rs:9:5
+   |
+LL |     <i32 as Add<i32>>::add(1, 2u32);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^----^
+   |                               |
+   |                               this argument influences the return type of `Add`
 note: associated function defined here
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: change the type of the numeric literal from `u32` to `i32`
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 bbd3eec2a54317a0e1df3451628d5c4762e5240a..ea737c567b96047f01e68084dd2bc7aa215ca689 100644 (file)
@@ -7,7 +7,7 @@ LL |     use Trait;
 help: consider importing this trait instead
    |
 LL |     use a::Trait;
-   |         ~~~~~~~~~
+   |         ~~~~~~~~
 
 error[E0405]: cannot find trait `Trait` in this scope
   --> $DIR/unresolved-candidates.rs:10:10
index f9732d02cb285c57fa06dff908511071f3387a19..4df2d8da3d6806ca5fa44b440f906204b1d329b0 100644 (file)
@@ -1,4 +1,4 @@
-error[E0208]: [o]
+error: [o]
   --> $DIR/variance-associated-consts.rs:13:1
    |
 LL | struct Foo<T: Trait> {
@@ -6,4 +6,3 @@ LL | struct Foo<T: Trait> {
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0208`.
index 1165fb53c7342ce80745c8882fe045500de42c93..ecb0821827dc0df4a3048f794defb55f700b6457 100644 (file)
@@ -10,7 +10,7 @@ fn method(&'a self) { }
 }
 
 #[rustc_variance]
-struct Foo<'a, T : Trait<'a>> { //~ ERROR [-, +]
+struct Foo<'a, T : Trait<'a>> { //~ ERROR [+, +]
     field: (T, &'a ())
 }
 
index 5ce62884e1d83ee15bf557e1a6271b6c6d34a753..70cb246f6e906da04ac481fdf156a070d1886aa3 100644 (file)
@@ -1,10 +1,10 @@
-error[E0208]: [-, +]
+error: [+, +]
   --> $DIR/variance-associated-types.rs:13:1
    |
 LL | struct Foo<'a, T : Trait<'a>> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [o, o]
+error: [o, o]
   --> $DIR/variance-associated-types.rs:18:1
    |
 LL | struct Bar<'a, T : Trait<'a>> {
@@ -12,4 +12,3 @@ LL | struct Bar<'a, T : Trait<'a>> {
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0208`.
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 1c3c1a6d1f223ce564326a353016f169af01485d..55a760425ee592e6ab24d38560e0967796b1c86e 100644 (file)
@@ -1,4 +1,4 @@
-error[E0208]: [o]
+error: [o]
   --> $DIR/variance-object-types.rs:7:1
    |
 LL | struct Foo<'a> {
@@ -6,4 +6,3 @@ LL | struct Foo<'a> {
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0208`.
index 3f34e7655f3a5ab0e3cc42916ba8d4a3dba82ffb..39ea77a8aa21a1a38c00e6b852149b10abfc25c6 100644 (file)
@@ -6,7 +6,7 @@
 // Regions that just appear in normal spots are contravariant:
 
 #[rustc_variance]
-struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -]
+struct Test2<'a, 'b, 'c> { //~ ERROR [+, +, +]
     x: &'a isize,
     y: &'b [isize],
     c: &'c str
@@ -15,7 +15,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -]
 // Those same annotations in function arguments become covariant:
 
 #[rustc_variance]
-struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +]
+struct Test3<'a, 'b, 'c> { //~ ERROR [-, -, -]
     x: extern "Rust" fn(&'a isize),
     y: extern "Rust" fn(&'b [isize]),
     c: extern "Rust" fn(&'c str),
@@ -24,7 +24,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +]
 // Mutability induces invariance:
 
 #[rustc_variance]
-struct Test4<'a, 'b:'a> { //~ ERROR [-, o]
+struct Test4<'a, 'b:'a> { //~ ERROR [+, o]
     x: &'a mut &'b isize,
 }
 
@@ -32,7 +32,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR [-, o]
 // contravariant context:
 
 #[rustc_variance]
-struct Test5<'a, 'b:'a> { //~ ERROR [+, o]
+struct Test5<'a, 'b:'a> { //~ ERROR [-, o]
     x: extern "Rust" fn(&'a mut &'b isize),
 }
 
@@ -42,7 +42,7 @@ struct Test5<'a, 'b:'a> { //~ ERROR [+, o]
 // argument list occurs in an invariant context.
 
 #[rustc_variance]
-struct Test6<'a, 'b:'a> { //~ ERROR [-, o]
+struct Test6<'a, 'b:'a> { //~ ERROR [+, o]
     x: &'a mut extern "Rust" fn(&'b isize),
 }
 
@@ -56,7 +56,7 @@ struct Test7<'a> { //~ ERROR [*]
 // Try enums too.
 
 #[rustc_variance]
-enum Test8<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
+enum Test8<'a, 'b, 'c:'b> { //~ ERROR [-, +, o]
     Test8A(extern "Rust" fn(&'a isize)),
     Test8B(&'b [isize]),
     Test8C(&'b mut &'c str),
index 27d69b6e82575d319506341a2e3b9b6204e6c980..c55730296f1c515ba98f8505150bdac43741898d 100644 (file)
@@ -1,40 +1,40 @@
-error[E0208]: [-, -, -]
+error: [+, +, +]
   --> $DIR/variance-regions-direct.rs:9:1
    |
 LL | struct Test2<'a, 'b, 'c> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [+, +, +]
+error: [-, -, -]
   --> $DIR/variance-regions-direct.rs:18:1
    |
 LL | struct Test3<'a, 'b, 'c> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [-, o]
+error: [+, o]
   --> $DIR/variance-regions-direct.rs:27:1
    |
 LL | struct Test4<'a, 'b:'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [+, o]
+error: [-, o]
   --> $DIR/variance-regions-direct.rs:35:1
    |
 LL | struct Test5<'a, 'b:'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [-, o]
+error: [+, o]
   --> $DIR/variance-regions-direct.rs:45:1
    |
 LL | struct Test6<'a, 'b:'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [*]
+error: [*]
   --> $DIR/variance-regions-direct.rs:52:1
    |
 LL | struct Test7<'a> {
    | ^^^^^^^^^^^^^^^^
 
-error[E0208]: [+, -, o]
+error: [-, +, o]
   --> $DIR/variance-regions-direct.rs:59:1
    |
 LL | enum Test8<'a, 'b, 'c:'b> {
@@ -42,4 +42,3 @@ LL | enum Test8<'a, 'b, 'c:'b> {
 
 error: aborting due to 7 previous errors
 
-For more information about this error, try `rustc --explain E0208`.
index f84f25ada14de88f5fd1886333ca507049aca389..0d00535fef11be78a41d87ed2be7b6c69d1f450a 100644 (file)
@@ -5,14 +5,14 @@
 #![feature(rustc_attrs)]
 
 #[rustc_variance]
-enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *]
+enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [-, +, o, *]
     Test8A(extern "Rust" fn(&'a isize)),
     Test8B(&'b [isize]),
     Test8C(&'b mut &'c str),
 }
 
 #[rustc_variance]
-struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, -, +]
+struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, +, -]
     f: Base<'z, 'y, 'x, 'w>
 }
 
@@ -22,12 +22,12 @@ struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *]
 }
 
 #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
-struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, -, *]
+struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, +, *]
     f: Base<'a, 'b, 'a, 'c>
 }
 
 #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here)
-struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
+struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [-, +, o]
     f: Base<'a, 'b, 'c, 'a>
 }
 
index 535e97db3fb10fce823aa4a53d9182ba5e0fadbc..edf2626d5984fffda8ea53dce6a032b03cc5612c 100644 (file)
@@ -1,28 +1,28 @@
-error[E0208]: [+, -, o, *]
+error: [-, +, o, *]
   --> $DIR/variance-regions-indirect.rs:8:1
    |
 LL | enum Base<'a, 'b, 'c:'b, 'd> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [*, o, -, +]
+error: [*, o, +, -]
   --> $DIR/variance-regions-indirect.rs:15:1
    |
 LL | struct Derived1<'w, 'x:'y, 'y, 'z> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [o, o, *]
+error: [o, o, *]
   --> $DIR/variance-regions-indirect.rs:20:1
    |
 LL | struct Derived2<'a, 'b:'a, 'c> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [o, -, *]
+error: [o, +, *]
   --> $DIR/variance-regions-indirect.rs:25:1
    |
 LL | struct Derived3<'a:'b, 'b, 'c> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [+, -, o]
+error: [-, +, o]
   --> $DIR/variance-regions-indirect.rs:30:1
    |
 LL | struct Derived4<'a, 'b, 'c:'b> {
@@ -30,4 +30,3 @@ LL | struct Derived4<'a, 'b, 'c:'b> {
 
 error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0208`.
index 3f6ca62a64069776d37fb0c7e966ef9f8be3c4ab..5a73e541c3a173d047232305e99b7fcb65a8c1a6 100644 (file)
@@ -1,22 +1,22 @@
-error[E0208]: [+, +]
+error: [+, +]
   --> $DIR/variance-trait-bounds.rs:16:1
    |
 LL | struct TestStruct<U,T:Setter<U>> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [*, +]
+error: [*, +]
   --> $DIR/variance-trait-bounds.rs:21:1
    |
 LL | enum TestEnum<U,T:Setter<U>> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [*, +]
+error: [*, +]
   --> $DIR/variance-trait-bounds.rs:26:1
    |
 LL | struct TestContraStruct<U,T:Setter<U>> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [*, +]
+error: [*, +]
   --> $DIR/variance-trait-bounds.rs:31:1
    |
 LL | struct TestBox<U,T:Getter<U>+Setter<U>> {
@@ -24,4 +24,3 @@ LL | struct TestBox<U,T:Getter<U>+Setter<U>> {
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0208`.
index ec3c973bc76395eba6e90c8250503e3707f4c19f..11303c465200574d018358e4479af4aeccc4aa1e 100644 (file)
@@ -11,7 +11,7 @@
 trait T { fn foo(&self); }
 
 #[rustc_variance]
-struct TOption<'a> { //~ ERROR [-]
+struct TOption<'a> { //~ ERROR [+]
     v: Option<Box<dyn T + 'a>>,
 }
 
index 9a2c924b96a9539fc07f2dde3508b91d12f09f96..bfcc8d4a1d11b058df1fd2bcc666016b332d1e31 100644 (file)
@@ -1,4 +1,4 @@
-error[E0208]: [-]
+error: [+]
   --> $DIR/variance-trait-object-bound.rs:14:1
    |
 LL | struct TOption<'a> {
@@ -6,4 +6,3 @@ LL | struct TOption<'a> {
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0208`.
index 523763b8a07b44340cf9f47e16278a6516a74d71..bb81644347693b4eb710565fffd2457f8a746ffb 100644 (file)
@@ -1,28 +1,28 @@
-error[E0208]: [+, +]
+error: [+, +]
   --> $DIR/variance-types-bounds.rs:7:1
    |
 LL | struct TestImm<A, B> {
    | ^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [+, o]
+error: [+, o]
   --> $DIR/variance-types-bounds.rs:13:1
    |
 LL | struct TestMut<A, B:'static> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [+, o]
+error: [+, o]
   --> $DIR/variance-types-bounds.rs:19:1
    |
 LL | struct TestIndirect<A:'static, B:'static> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [o, o]
+error: [o, o]
   --> $DIR/variance-types-bounds.rs:24:1
    |
 LL | struct TestIndirect2<A:'static, B:'static> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [o, o]
+error: [o, o]
   --> $DIR/variance-types-bounds.rs:38:1
    |
 LL | struct TestObject<A, R> {
@@ -30,4 +30,3 @@ LL | struct TestObject<A, R> {
 
 error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0208`.
index b9b6d9c9bb5e4679dd6bfbbdb5e7519d18729c51..cfc03b754734d156bca8d87e8dcd94cf0b75ff81 100644 (file)
@@ -7,7 +7,7 @@
 // not considered bivariant.
 
 #[rustc_variance]
-struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [-, o, o]
+struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [+, o, o]
     t: &'a mut (A,B)
 }
 
index 5a5aaecffc5eb8d32ecb0b6b211cc25a66fbb1b4..0fda4b8036e721ac941487f3ad2b29a3f5bde26b 100644 (file)
@@ -1,34 +1,34 @@
-error[E0208]: [-, o, o]
+error: [+, o, o]
   --> $DIR/variance-types.rs:10:1
    |
 LL | struct InvariantMut<'a,A:'a,B:'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [o]
+error: [o]
   --> $DIR/variance-types.rs:15:1
    |
 LL | struct InvariantCell<A> {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [o]
+error: [o]
   --> $DIR/variance-types.rs:20:1
    |
 LL | struct InvariantIndirect<A> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [+]
+error: [+]
   --> $DIR/variance-types.rs:25:1
    |
 LL | struct Covariant<A> {
    | ^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [-]
+error: [-]
   --> $DIR/variance-types.rs:30:1
    |
 LL | struct Contravariant<A> {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0208]: [+, -, o]
+error: [+, -, o]
   --> $DIR/variance-types.rs:35:1
    |
 LL | enum Enum<A,B,C> {
@@ -36,4 +36,3 @@ LL | enum Enum<A,B,C> {
 
 error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0208`.
index 914b52cf041dbdf5be1802a1cadc6561fad571a5..79958729fc521ed1ada06422e092a769384d2377 100644 (file)
@@ -175,7 +175,7 @@ exclude_labels = [
     "T-*",
 ]
 
-[autolabel."A-bootstrap"]
+[autolabel."T-bootstrap"]
 trigger_files = [
     "x.py",
     "x",
@@ -185,7 +185,6 @@ trigger_files = [
     "src/tools/x",
     "configure",
     "Cargo.toml",
-    "Cargo.lock",
     "config.toml.example",
     "src/stage0.json"
 ]
@@ -251,7 +250,7 @@ new_pr = true
 
 [autolabel."WG-trait-system-refactor"]
 trigger_files = [
-    "compiler/rustc_trait_selection/solve"
+    "compiler/rustc_trait_selection/src/solve"
 ]
 
 [notify-zulip."I-prioritize"]
@@ -457,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"
@@ -494,6 +496,8 @@ libs = [
 ]
 bootstrap = [
     "@Mark-Simulacrum",
+    "@albertlarsan68",
+    "@ozkanonur",
 ]
 infra-ci = [
     "@Mark-Simulacrum",
@@ -559,6 +563,12 @@ ast_lowering = [
 fallback = [
     "@Mark-Simulacrum"
 ]
+style-team = [
+    "@calebcartwright",
+    "@compiler-errors",
+    "@joshtriplett",
+    "@yaahc",
+]
 
 [assign.owners]
 "/.github/workflows" =                       ["infra-ci"]
@@ -603,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"]