]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #107656 - jonhoo:bump-rust-installer, r=Mark-Simulacrum
authorMatthias Krüger <matthias.krueger@famsik.de>
Wed, 8 Feb 2023 06:13:26 +0000 (07:13 +0100)
committerGitHub <noreply@github.com>
Wed, 8 Feb 2023 06:13:26 +0000 (07:13 +0100)
Bump rust-installer

Makes generation of `manifest.in` deterministic:
https://github.com/rust-lang/rust-installer/pull/120

370 files changed:
.github/workflows/ci.yml
.mailmap
Cargo.lock
compiler/rustc/Cargo.toml
compiler/rustc_abi/src/lib.rs
compiler/rustc_ast_lowering/Cargo.toml
compiler/rustc_ast_pretty/Cargo.toml
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/mod.rs
compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_codegen_llvm/Cargo.toml
compiler/rustc_codegen_ssa/Cargo.toml
compiler/rustc_codegen_ssa/src/mir/rvalue.rs
compiler/rustc_const_eval/Cargo.toml
compiler/rustc_const_eval/src/interpret/discriminant.rs [new file with mode: 0644]
compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/mod.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/interpret/step.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/check_consts/ops.rs
compiler/rustc_const_eval/src/transform/validate.rs
compiler/rustc_const_eval/src/util/aggregate.rs [deleted file]
compiler/rustc_const_eval/src/util/mod.rs
compiler/rustc_driver/Cargo.toml
compiler/rustc_driver/README.md [deleted file]
compiler/rustc_driver/src/args.rs [deleted file]
compiler/rustc_driver/src/lib.rs
compiler/rustc_driver/src/pretty.rs [deleted file]
compiler/rustc_driver/src/session_diagnostics.rs [deleted file]
compiler/rustc_driver_impl/Cargo.toml [new file with mode: 0644]
compiler/rustc_driver_impl/README.md [new file with mode: 0644]
compiler/rustc_driver_impl/src/args.rs [new file with mode: 0644]
compiler/rustc_driver_impl/src/lib.rs [new file with mode: 0644]
compiler/rustc_driver_impl/src/pretty.rs [new file with mode: 0644]
compiler/rustc_driver_impl/src/session_diagnostics.rs [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0464.md
compiler/rustc_error_codes/src/error_codes/E0523.md [new file with mode: 0644]
compiler/rustc_error_messages/locales/en-US/borrowck.ftl
compiler/rustc_error_messages/locales/en-US/driver.ftl
compiler/rustc_error_messages/locales/en-US/lint.ftl
compiler/rustc_error_messages/locales/en-US/parse.ftl
compiler/rustc_errors/src/emitter.rs
compiler/rustc_expand/src/base.rs
compiler/rustc_hir_analysis/Cargo.toml
compiler/rustc_hir_analysis/src/astconv/mod.rs
compiler/rustc_hir_analysis/src/coherence/builtin.rs
compiler/rustc_hir_analysis/src/collect.rs
compiler/rustc_hir_analysis/src/collect/type_of.rs
compiler/rustc_hir_typeck/src/demand.rs
compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs [new file with mode: 0644]
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/method/probe.rs
compiler/rustc_hir_typeck/src/op.rs
compiler/rustc_infer/Cargo.toml
compiler/rustc_infer/src/infer/canonical/query_response.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
compiler/rustc_infer/src/infer/freshen.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/nll_relate/mod.rs
compiler/rustc_infer/src/infer/resolve.rs
compiler/rustc_infer/src/traits/util.rs
compiler/rustc_interface/Cargo.toml
compiler/rustc_interface/src/passes.rs
compiler/rustc_lint/src/lints.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
compiler/rustc_metadata/src/creader.rs
compiler/rustc_metadata/src/errors.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/infer/canonical.rs
compiler/rustc_middle/src/mir/interpret/error.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/syntax.rs
compiler/rustc_middle/src/mir/tcx.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/traits/solve.rs [new file with mode: 0644]
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/diagnostics.rs
compiler/rustc_middle/src/ty/fold.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_mir_build/Cargo.toml
compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
compiler/rustc_mir_dataflow/Cargo.toml
compiler/rustc_mir_dataflow/src/value_analysis.rs
compiler/rustc_mir_transform/src/check_unsafety.rs
compiler/rustc_mir_transform/src/copy_prop.rs
compiler/rustc_mir_transform/src/dataflow_const_prop.rs
compiler/rustc_mir_transform/src/deaggregator.rs [deleted file]
compiler/rustc_mir_transform/src/generator.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_mir_transform/src/shim.rs
compiler/rustc_mir_transform/src/sroa.rs
compiler/rustc_parse/src/errors.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/generics.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/parser/stmt.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_privacy/Cargo.toml
compiler/rustc_query_impl/Cargo.toml
compiler/rustc_query_system/src/query/caches.rs
compiler/rustc_query_system/src/query/config.rs
compiler/rustc_query_system/src/query/plumbing.rs
compiler/rustc_session/src/code_stats.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/src/def_id.rs
compiler/rustc_trait_selection/Cargo.toml
compiler/rustc_trait_selection/src/solve/mod.rs
compiler/rustc_trait_selection/src/solve/search_graph/cache.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_traits/Cargo.toml
compiler/rustc_ty_utils/src/abi.rs
compiler/rustc_ty_utils/src/assoc.rs
compiler/rustc_ty_utils/src/layout.rs
compiler/rustc_type_ir/src/lib.rs
library/core/src/cmp.rs
library/core/src/const_closure.rs [deleted file]
library/core/src/iter/adapters/array_chunks.rs
library/core/src/iter/adapters/by_ref_sized.rs
library/core/src/iter/mod.rs
library/core/src/lib.rs
library/core/src/num/uint_macros.rs
library/core/src/ops/arith.rs
library/core/src/ops/try_trait.rs
library/core/src/option.rs
library/core/src/sync/atomic.rs
library/std/src/collections/hash/map.rs
library/std/src/f32.rs
library/std/src/f64.rs
library/std/src/io/error.rs
library/std/src/io/error/repr_bitpacked.rs
library/std/src/io/error/repr_unpacked.rs
library/std/src/io/error/tests.rs
library/std/src/io/mod.rs
src/bootstrap/README.md
src/bootstrap/lib.rs
src/bootstrap/test.rs
src/ci/github-actions/ci.yml
src/ci/scripts/should-skip-this.sh
src/ci/stage-build.py
src/doc/rustc/book.toml
src/doc/rustc/src/codegen-options/index.md
src/librustdoc/html/format.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/js/search.js
src/librustdoc/html/templates/page.html
src/librustdoc/markdown.rs
src/tools/expand-yaml-anchors/src/main.rs
src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
src/tools/miri/src/intptrcast.rs
src/tools/miri/src/machine.rs
src/tools/miri/src/shims/backtrace.rs
src/tools/miri/src/shims/panic.rs
src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.rs [deleted file]
src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.stderr [deleted file]
src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs
src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs
src/tools/tidy/src/error_codes.rs
src/tools/tidy/src/ui_tests.rs
tests/codegen/function-arguments-noopt.rs
tests/codegen/function-arguments.rs
tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir
tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
tests/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
tests/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff
tests/mir-opt/const_prop/aggregate.foo.ConstProp.diff [new file with mode: 0644]
tests/mir-opt/const_prop/aggregate.foo.PreCodegen.after.mir [new file with mode: 0644]
tests/mir-opt/const_prop/aggregate.main.ConstProp.diff
tests/mir-opt/const_prop/aggregate.main.PreCodegen.after.mir
tests/mir-opt/const_prop/aggregate.rs
tests/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff
tests/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff
tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff
tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff
tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff
tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff
tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
tests/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff
tests/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff
tests/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.32bit.mir
tests/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.64bit.mir
tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.diff
tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.diff
tests/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.32bit.mir
tests/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.64bit.mir
tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff
tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff
tests/mir-opt/copy-prop/issue_107511.main.CopyProp.diff
tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/move_projection.rs [new file with mode: 0644]
tests/mir-opt/dataflow-const-prop/enum.main.DataflowConstProp.diff
tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff
tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff
tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.diff
tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.diff
tests/mir-opt/deaggregator_test.bar.Deaggregator.diff [deleted file]
tests/mir-opt/deaggregator_test.rs [deleted file]
tests/mir-opt/deaggregator_test_enum.bar.Deaggregator.diff [deleted file]
tests/mir-opt/deaggregator_test_enum.rs [deleted file]
tests/mir-opt/deaggregator_test_enum_2.rs [deleted file]
tests/mir-opt/deaggregator_test_enum_2.test1.Deaggregator.diff [deleted file]
tests/mir-opt/deaggregator_test_multiple.rs [deleted file]
tests/mir-opt/deaggregator_test_multiple.test.Deaggregator.diff [deleted file]
tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
tests/mir-opt/inline/cycle.f.Inline.diff
tests/mir-opt/inline/inline_closure.foo.Inline.after.mir
tests/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
tests/mir-opt/inline/inline_diverging.h.Inline.diff
tests/mir-opt/inline/inline_generator.main.Inline.diff
tests/mir-opt/inline/inline_into_box_place.main.Inline.diff
tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
tests/mir-opt/inline/issue_78442.bar.Inline.diff
tests/mir-opt/inline/issue_78442.bar.RevealAll.diff
tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
tests/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff
tests/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff
tests/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
tests/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
tests/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
tests/mir-opt/remove_zsts.get_union.PreCodegen.after.mir
tests/mir-opt/remove_zsts.get_union.RemoveZsts.diff
tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff
tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir
tests/mir-opt/simplify_locals.d1.SimplifyLocals-before-const-prop.diff
tests/mir-opt/simplify_locals.d2.SimplifyLocals-before-const-prop.diff
tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff
tests/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.diff
tests/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals-before-const-prop.diff
tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff [new file with mode: 0644]
tests/mir-opt/sroa.dropping.ScalarReplacementOfAggregates.diff
tests/mir-opt/sroa.enums.ScalarReplacementOfAggregates.diff
tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff
tests/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff
tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff [new file with mode: 0644]
tests/mir-opt/sroa.rs
tests/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff
tests/mir-opt/sroa.unions.ScalarReplacementOfAggregates.diff
tests/mir-opt/try_identity_e2e.new.PreCodegen.after.mir
tests/mir-opt/try_identity_e2e.old.PreCodegen.after.mir
tests/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
tests/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff
tests/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
tests/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff
tests/mir-opt/unusual_item_types.Test-X-{constructor#0}.built.after.mir
tests/mir-opt/while_let_loops.change_loop_body.ConstProp.diff
tests/rustdoc-gui/src/test_docs/lib.rs
tests/rustdoc-js-std/regex.js [new file with mode: 0644]
tests/rustdoc-js-std/typed-query.js
tests/rustdoc-js/doc-alias.js
tests/rustdoc-js/module-substring.js
tests/rustdoc/auxiliary/inline-default-methods.rs
tests/rustdoc/decl-trailing-whitespace.declaration.html
tests/rustdoc/doc-notable_trait.some-struct-new.html
tests/rustdoc/doc-notable_trait.wrap-me.html
tests/rustdoc/inline-default-methods.rs
tests/rustdoc/issue-85454.rs
tests/rustdoc/where.SWhere_TraitWhere_item-decl.html
tests/rustdoc/where.rs
tests/rustdoc/whitespace-after-where-clause.enum2.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.union2.html
tests/ui/associated-types/hr-associated-type-projection-1.stderr
tests/ui/async-await/future-sizes/async-awaiting-fut.rs [new file with mode: 0644]
tests/ui/async-await/future-sizes/async-awaiting-fut.stdout [new file with mode: 0644]
tests/ui/async-await/future-sizes/large-arg.stdout
tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr
tests/ui/borrowck/issue-85765.rs
tests/ui/borrowck/issue-85765.stderr
tests/ui/borrowck/issue-91206.rs
tests/ui/borrowck/issue-91206.stderr
tests/ui/borrowck/issue-92015.stderr
tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_binop_arg_tys.rs [new file with mode: 0644]
tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_binop_arg_tys.stderr [new file with mode: 0644]
tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_cast_arg_ty.rs [new file with mode: 0644]
tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_cast_arg_ty.stderr [new file with mode: 0644]
tests/ui/consts/const-err-late.stderr
tests/ui/derives/deriving-copyclone.stderr
tests/ui/error-codes/E0523.rs [new file with mode: 0644]
tests/ui/error-codes/E0523.stderr [new file with mode: 0644]
tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs [new file with mode: 0644]
tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr [new file with mode: 0644]
tests/ui/errors/traits/blame-trait-error-spans-on-exprs.rs [new file with mode: 0644]
tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr [new file with mode: 0644]
tests/ui/generic-associated-types/issue-68656-unsized-values.stderr
tests/ui/generic-associated-types/missing-bounds.fixed
tests/ui/generic-associated-types/missing-bounds.stderr
tests/ui/issues/issue-51515.rs
tests/ui/issues/issue-51515.stderr
tests/ui/issues/issue-92741.fixed [new file with mode: 0644]
tests/ui/issues/issue-92741.rs [new file with mode: 0644]
tests/ui/issues/issue-92741.stderr [new file with mode: 0644]
tests/ui/lifetimes/issue-107492-default-value-for-lifetime.rs [new file with mode: 0644]
tests/ui/lifetimes/issue-107492-default-value-for-lifetime.stderr [new file with mode: 0644]
tests/ui/lint/unused/issue-103320-must-use-ops.rs [new file with mode: 0644]
tests/ui/lint/unused/issue-103320-must-use-ops.stderr [new file with mode: 0644]
tests/ui/malformed/issue-107423-unused-delim-only-one-no-pair.rs [new file with mode: 0644]
tests/ui/malformed/issue-107423-unused-delim-only-one-no-pair.stderr [new file with mode: 0644]
tests/ui/mir/issue-107678-projection-with-lifetime.rs [new file with mode: 0644]
tests/ui/mir/issue-107691.rs [new file with mode: 0644]
tests/ui/parser/missing-expression-in-for-loop.rs [new file with mode: 0644]
tests/ui/parser/missing-expression-in-for-loop.stderr [new file with mode: 0644]
tests/ui/parser/recover-quantified-closure.rs
tests/ui/parser/recover-quantified-closure.stderr
tests/ui/print_type_sizes/async.stdout
tests/ui/print_type_sizes/generator.stdout
tests/ui/print_type_sizes/generator_discr_placement.stdout
tests/ui/recursion/issue-83150.stderr
tests/ui/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs [new file with mode: 0644]
tests/ui/suggest-null-ptr.fixed [new file with mode: 0644]
tests/ui/suggest-null-ptr.rs [new file with mode: 0644]
tests/ui/suggest-null-ptr.stderr [new file with mode: 0644]
tests/ui/suggestions/restrict-existing-type-bounds.rs [new file with mode: 0644]
tests/ui/suggestions/restrict-existing-type-bounds.stderr [new file with mode: 0644]
tests/ui/suggestions/suggest-fn-ptr-for-fn-item-in-fn-ret.fixed [new file with mode: 0644]
tests/ui/suggestions/suggest-fn-ptr-for-fn-item-in-fn-ret.rs [new file with mode: 0644]
tests/ui/suggestions/suggest-fn-ptr-for-fn-item-in-fn-ret.stderr [new file with mode: 0644]
tests/ui/suggestions/type-mismatch-byte-literal.rs
tests/ui/suggestions/type-mismatch-byte-literal.stderr
tests/ui/traits/negative-impls/negated-auto-traits-error.stderr
tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs [new file with mode: 0644]
tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr [new file with mode: 0644]
triagebot.toml

index a992129773e2967f8f411fdf7fb33e58620a467f..b51105750c82cc9aa428298d520959ab20071409 100644 (file)
@@ -60,9 +60,8 @@ jobs:
             env: {}
           - name: x86_64-gnu-tools
             tidy: false
-            env:
-              CI_ONLY_WHEN_SUBMODULES_CHANGED: 1
             os: ubuntu-20.04-xl
+            env: {}
     timeout-minutes: 600
     runs-on: "${{ matrix.os }}"
     steps:
index 8ed692989ccbf73baf3dbe06012380237c5b3a56..b814767786f2af8b235793fc32708fcda2459a55 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -166,6 +166,7 @@ Eduard-Mihai Burtescu <edy.burt@gmail.com>
 Eduardo Bautista <me@eduardobautista.com> <=>
 Eduardo Bautista <me@eduardobautista.com> <mail@eduardobautista.com>
 Eduardo Broto <ebroto@tutanota.com>
+Edward Shen <code@eddie.sh> <xes@meta.com>
 Elliott Slaughter <elliottslaughter@gmail.com> <eslaughter@mozilla.com>
 Elly Fong-Jones <elly@leptoquark.net>
 Eric Holk <eric.holk@gmail.com> <eholk@cs.indiana.edu>
index 14758d0f07ef351f1cf1ec1899418bb477342ddc..b2948fb38959e8df8c256f68ade4377609037f7f 100644 (file)
@@ -3567,6 +3567,7 @@ dependencies = [
  "jemalloc-sys",
  "rustc_codegen_ssa",
  "rustc_driver",
+ "rustc_driver_impl",
  "rustc_smir",
 ]
 
@@ -3688,7 +3689,6 @@ dependencies = [
 name = "rustc_ast_lowering"
 version = "0.0.0"
 dependencies = [
- "rustc_arena",
  "rustc_ast",
  "rustc_ast_pretty",
  "rustc_data_structures",
@@ -3697,7 +3697,6 @@ dependencies = [
  "rustc_index",
  "rustc_macros",
  "rustc_middle",
- "rustc_query_system",
  "rustc_session",
  "rustc_span",
  "rustc_target",
@@ -3730,7 +3729,6 @@ name = "rustc_ast_pretty"
 version = "0.0.0"
 dependencies = [
  "rustc_ast",
- "rustc_parse_format",
  "rustc_span",
 ]
 
@@ -3837,7 +3835,6 @@ dependencies = [
  "rustc_metadata",
  "rustc_middle",
  "rustc_query_system",
- "rustc_serialize",
  "rustc_session",
  "rustc_span",
  "rustc_symbol_mangling",
@@ -3863,7 +3860,6 @@ dependencies = [
  "rustc_arena",
  "rustc_ast",
  "rustc_attr",
- "rustc_const_eval",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fs_util",
@@ -3904,7 +3900,6 @@ dependencies = [
  "rustc_macros",
  "rustc_middle",
  "rustc_mir_dataflow",
- "rustc_query_system",
  "rustc_session",
  "rustc_span",
  "rustc_target",
@@ -3946,6 +3941,13 @@ dependencies = [
 [[package]]
 name = "rustc_driver"
 version = "0.0.0"
+dependencies = [
+ "rustc_driver_impl",
+]
+
+[[package]]
+name = "rustc_driver_impl"
+version = "0.0.0"
 dependencies = [
  "libc",
  "rustc_ast",
@@ -4092,15 +4094,12 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_feature",
- "rustc_graphviz",
  "rustc_hir",
- "rustc_hir_pretty",
  "rustc_index",
  "rustc_infer",
  "rustc_lint",
  "rustc_macros",
  "rustc_middle",
- "rustc_serialize",
  "rustc_session",
  "rustc_span",
  "rustc_target",
@@ -4187,7 +4186,6 @@ dependencies = [
  "rustc_macros",
  "rustc_middle",
  "rustc_serialize",
- "rustc_session",
  "rustc_span",
  "rustc_target",
  "smallvec",
@@ -4230,7 +4228,6 @@ dependencies = [
  "rustc_privacy",
  "rustc_query_impl",
  "rustc_resolve",
- "rustc_serialize",
  "rustc_session",
  "rustc_span",
  "rustc_symbol_mangling",
@@ -4396,7 +4393,6 @@ dependencies = [
  "rustc_apfloat",
  "rustc_arena",
  "rustc_ast",
- "rustc_attr",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_hir",
@@ -4428,7 +4424,6 @@ dependencies = [
  "rustc_macros",
  "rustc_middle",
  "rustc_serialize",
- "rustc_session",
  "rustc_span",
  "rustc_target",
  "smallvec",
@@ -4559,7 +4554,6 @@ dependencies = [
  "rustc_middle",
  "rustc_session",
  "rustc_span",
- "rustc_trait_selection",
  "tracing",
 ]
 
@@ -4580,7 +4574,6 @@ dependencies = [
  "rustc_serialize",
  "rustc_session",
  "rustc_span",
- "rustc_target",
  "thin-vec",
  "tracing",
 ]
@@ -4781,7 +4774,6 @@ dependencies = [
  "rustc_hir",
  "rustc_index",
  "rustc_infer",
- "rustc_lint_defs",
  "rustc_macros",
  "rustc_middle",
  "rustc_parse_format",
@@ -4803,7 +4795,6 @@ dependencies = [
  "chalk-ir",
  "chalk-solve",
  "rustc_ast",
- "rustc_attr",
  "rustc_data_structures",
  "rustc_hir",
  "rustc_index",
index 27ee3dd2aeafc7086cde881e22713d73006800e8..41003ad83f31152956dce55a9feb2623f6b4fcc9 100644 (file)
@@ -5,6 +5,7 @@ edition = "2021"
 
 [dependencies]
 rustc_driver = { path = "../rustc_driver" }
+rustc_driver_impl = { path = "../rustc_driver_impl" }
 
 # Make sure rustc_codegen_ssa ends up in the sysroot, because this
 # crate is intended to be used by codegen backends, which may not be in-tree.
@@ -20,6 +21,6 @@ features = ['unprefixed_malloc_on_supported_platforms']
 
 [features]
 jemalloc = ['jemalloc-sys']
-llvm = ['rustc_driver/llvm']
-max_level_info = ['rustc_driver/max_level_info']
-rustc_use_parallel_compiler = ['rustc_driver/rustc_use_parallel_compiler']
+llvm = ['rustc_driver_impl/llvm']
+max_level_info = ['rustc_driver_impl/max_level_info']
+rustc_use_parallel_compiler = ['rustc_driver_impl/rustc_use_parallel_compiler']
index 5af6206c0bb80dcabec6169f2ec00aabfd3ca146..0306cb5ce6abd7615d068c093cff045333e2e26b 100644 (file)
@@ -1439,21 +1439,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum PointerKind {
-    /// Most general case, we know no restrictions to tell LLVM.
-    SharedMutable,
-
-    /// `&T` where `T` contains no `UnsafeCell`, is `dereferenceable`, `noalias` and `readonly`.
-    Frozen,
-
-    /// `&mut T` which is `dereferenceable` and `noalias` but not `readonly`.
-    UniqueBorrowed,
-
-    /// `&mut !Unpin`, which is `dereferenceable` but neither `noalias` nor `readonly`.
-    UniqueBorrowedPinned,
-
-    /// `Box<T>`, which is `noalias` (even on return types, unlike the above) but neither `readonly`
-    /// nor `dereferenceable`.
-    UniqueOwned,
+    /// Shared reference. `frozen` indicates the absence of any `UnsafeCell`.
+    SharedRef { frozen: bool },
+    /// Mutable reference. `unpin` indicates the absence of any pinned data.
+    MutableRef { unpin: bool },
+    /// Box. `unpin` indicates the absence of any pinned data.
+    Box { unpin: bool },
 }
 
 /// Note that this information is advisory only, and backends are free to ignore it.
index 6a59b9e6151ce13554f9901e95e88ca75d06153d..6e76c349a4a048bd2c4d8fb07b95db8774ec244f 100644 (file)
@@ -7,7 +7,6 @@ edition = "2021"
 doctest = false
 
 [dependencies]
-rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_data_structures = { path = "../rustc_data_structures" }
@@ -16,7 +15,6 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_macros = { path = "../rustc_macros" }
-rustc_query_system = { path = "../rustc_query_system" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
index b4900dc39a8af4d98913c75f26146923df617714..d1513c114fef4a960558120c63d9c08188723e29 100644 (file)
@@ -7,5 +7,4 @@ edition = "2021"
 
 [dependencies]
 rustc_ast = { path = "../rustc_ast" }
-rustc_parse_format = { path = "../rustc_parse_format" }
 rustc_span = { path = "../rustc_span" }
index 50c0faf4597f1a2cdb36f0a085b0e09e2533cc8a..7b07c2a463371d531fa5ee6c3569492cacd2cd49 100644 (file)
@@ -803,6 +803,7 @@ fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: S
                 predicates
                     .iter()
                     .map(|(param, constraint)| (param.name.as_str(), &**constraint, None)),
+                None,
             );
         }
     }
@@ -2645,6 +2646,7 @@ fn annotate_argument_and_return_for_borrow(
                             operands,
                         ) = rvalue
                         {
+                            let def_id = def_id.expect_local();
                             for operand in operands {
                                 let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else {
                                     continue;
@@ -2667,7 +2669,7 @@ fn annotate_argument_and_return_for_borrow(
                                 // into a place then we should annotate the closure in
                                 // case it ends up being assigned into the return place.
                                 annotated_closure =
-                                    self.annotate_fn_sig(*def_id, substs.as_closure().sig());
+                                    self.annotate_fn_sig(def_id, substs.as_closure().sig());
                                 debug!(
                                     "annotate_argument_and_return_for_borrow: \
                                      annotated_closure={:?} assigned_from_local={:?} \
index 8c579bac7e8eb471c8dc8690eb7f7c3a7c62c5d1..a75ec87be4cac0721b6cdfc58fa3b095c7959048 100644 (file)
@@ -817,6 +817,7 @@ pub(super) fn move_spans(
             && let AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) = **kind
         {
             debug!("move_spans: def_id={:?} places={:?}", def_id, places);
+            let def_id = def_id.expect_local();
             if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
                 self.closure_span(def_id, moved_place, places)
             {
@@ -945,6 +946,7 @@ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpan
                     box AggregateKind::Generator(def_id, _, _) => (def_id, true),
                     _ => continue,
                 };
+                let def_id = def_id.expect_local();
 
                 debug!(
                     "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
index 40f518b33cfb66dbcf4b485a2d32ab3a71b2aa1a..9f37b915b773a7e611f1aa6d0bc48bcd4a7a5d41 100644 (file)
@@ -606,12 +606,63 @@ pub(crate) fn report_mutability_error(
                                 }
                             }
                             Some((false, err_label_span, message)) => {
-                                err.span_label(
-                                    err_label_span,
-                                    &format!(
-                                        "consider changing this binding's type to be: `{message}`"
-                                    ),
-                                );
+                                struct BindingFinder {
+                                    span: Span,
+                                    hir_id: Option<hir::HirId>,
+                                }
+
+                                impl<'tcx> Visitor<'tcx> for BindingFinder {
+                                    fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
+                                        if let hir::StmtKind::Local(local) = s.kind {
+                                            if local.pat.span == self.span {
+                                                self.hir_id = Some(local.hir_id);
+                                            }
+                                        }
+                                        hir::intravisit::walk_stmt(self, s);
+                                    }
+                                }
+                                let hir_map = self.infcx.tcx.hir();
+                                let def_id = self.body.source.def_id();
+                                let hir_id = hir_map.local_def_id_to_hir_id(def_id.expect_local());
+                                let node = hir_map.find(hir_id);
+                                let hir_id = if let Some(hir::Node::Item(item)) = node
+                                    && let hir::ItemKind::Fn(.., body_id) = item.kind
+                                {
+                                    let body = hir_map.body(body_id);
+                                    let mut v = BindingFinder {
+                                        span: err_label_span,
+                                        hir_id: None,
+                                    };
+                                    v.visit_body(body);
+                                    v.hir_id
+                                } else {
+                                    None
+                                };
+                                if let Some(hir_id) = hir_id
+                                    && let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
+                                {
+                                    let (changing, span, sugg) = match local.ty {
+                                        Some(ty) => ("changing", ty.span, message),
+                                        None => (
+                                            "specifying",
+                                            local.pat.span.shrink_to_hi(),
+                                            format!(": {message}"),
+                                        ),
+                                    };
+                                    err.span_suggestion_verbose(
+                                        span,
+                                        &format!("consider {changing} this binding's type"),
+                                        sugg,
+                                        Applicability::HasPlaceholders,
+                                    );
+                                } else {
+                                    err.span_label(
+                                        err_label_span,
+                                        &format!(
+                                            "consider changing this binding's type to be: `{message}`"
+                                        ),
+                                    );
+                                }
                             }
                             None => {}
                         }
index bc81abe4005c919467114d502173cf017e0ab308..98103af779d8b5fbc157abb6418f960bd0edc67f 100644 (file)
@@ -1278,6 +1278,7 @@ fn consume_rvalue(
                 // in order to populate our used_mut set.
                 match **aggregate_kind {
                     AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) => {
+                        let def_id = def_id.expect_local();
                         let BorrowCheckResult { used_mut_upvars, .. } =
                             self.infcx.tcx.mir_borrowck(def_id);
                         debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
index e15d1b99ad205229e2d7b901e101da1bcc5614b5..1dc6c42fbf78ea3a4b60f27ec9370de3bcad73d2 100644 (file)
@@ -83,16 +83,8 @@ pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<
         }
         self.constraints.member_constraints = tmp;
 
-        for (predicate, constraint_category) in outlives {
-            // At the moment, we never generate any "higher-ranked"
-            // region constraints like `for<'a> 'a: 'b`. At some point
-            // when we move to universes, we will, and this assertion
-            // will start to fail.
-            let predicate = predicate.no_bound_vars().unwrap_or_else(|| {
-                bug!("query_constraint {:?} contained bound vars", predicate,);
-            });
-
-            self.convert(predicate, *constraint_category);
+        for &(predicate, constraint_category) in outlives {
+            self.convert(predicate, constraint_category);
         }
     }
 
index 6c67e1a00c35c38a8b119cb6c9ceec5715b3bae6..5b52846562f87f64db5d65d5095c64850fd11904 100644 (file)
@@ -2536,7 +2536,7 @@ fn prove_aggregate_predicates(
             // clauses on the struct.
             AggregateKind::Closure(def_id, substs)
             | AggregateKind::Generator(def_id, substs, _) => {
-                (def_id.to_def_id(), self.prove_closure_bounds(tcx, def_id, substs, location))
+                (def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location))
             }
 
             AggregateKind::Array(_) | AggregateKind::Tuple => {
index 9c1bcd431ec4933b2d858b5d6eb21bcffbfabe69..773c0ebbe59db8ce86121f8fd678368c0c1f8f9a 100644 (file)
@@ -30,7 +30,6 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_metadata = { path = "../rustc_metadata" }
 rustc_query_system = { path = "../rustc_query_system" }
 rustc_session = { path = "../rustc_session" }
-rustc_serialize = { path = "../rustc_serialize" }
 rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
 rustc_target = { path = "../rustc_target" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
index 0d2d2ec68a23f3adf9ac9d928d0a435bb67c6c9b..c55991e00d3ae864e0cab69dbc54b9b125a8910a 100644 (file)
@@ -41,7 +41,6 @@ rustc_metadata = { path = "../rustc_metadata" }
 rustc_query_system = { path = "../rustc_query_system" }
 rustc_target = { path = "../rustc_target" }
 rustc_session = { path = "../rustc_session" }
-rustc_const_eval = { path = "../rustc_const_eval" }
 
 [dependencies.object]
 version = "0.30.1"
index 23196c8cbaea1ebf4f3d9c9e9d82ab681d9aa5b6..35948e50f48d0da28aa8e27f53936be7160df860 100644 (file)
@@ -13,6 +13,7 @@
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
 use rustc_span::source_map::{Span, DUMMY_SP};
+use rustc_target::abi::VariantIdx;
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     #[instrument(level = "trace", skip(self, bx))]
@@ -106,17 +107,16 @@ pub fn codegen_rvalue(
             }
 
             mir::Rvalue::Aggregate(ref kind, ref operands) => {
-                let (dest, active_field_index) = match **kind {
-                    mir::AggregateKind::Adt(adt_did, variant_index, _, _, active_field_index) => {
-                        dest.codegen_set_discr(bx, variant_index);
-                        if bx.tcx().adt_def(adt_did).is_enum() {
-                            (dest.project_downcast(bx, variant_index), active_field_index)
-                        } else {
-                            (dest, active_field_index)
-                        }
+                let (variant_index, variant_dest, active_field_index) = match **kind {
+                    mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => {
+                        let variant_dest = dest.project_downcast(bx, variant_index);
+                        (variant_index, variant_dest, active_field_index)
                     }
-                    _ => (dest, None),
+                    _ => (VariantIdx::from_u32(0), dest, None),
                 };
+                if active_field_index.is_some() {
+                    assert_eq!(operands.len(), 1);
+                }
                 for (i, operand) in operands.iter().enumerate() {
                     let op = self.codegen_operand(bx, operand);
                     // Do not generate stores and GEPis for zero-sized fields.
@@ -124,13 +124,14 @@ pub fn codegen_rvalue(
                         let field_index = active_field_index.unwrap_or(i);
                         let field = if let mir::AggregateKind::Array(_) = **kind {
                             let llindex = bx.cx().const_usize(field_index as u64);
-                            dest.project_index(bx, llindex)
+                            variant_dest.project_index(bx, llindex)
                         } else {
-                            dest.project_field(bx, field_index)
+                            variant_dest.project_field(bx, field_index)
                         };
                         op.val.store(bx, field);
                     }
                 }
+                dest.codegen_set_discr(bx, variant_index);
             }
 
             _ => {
index 51489e2936068c8519ddae244ec0006912098e2e..98ac36c1ced73bf5d12e7565f54bdec939d96c62 100644 (file)
@@ -19,7 +19,6 @@ rustc_infer = { path = "../rustc_infer" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
-rustc_query_system = { path = "../rustc_query_system" }
 rustc_session = { path = "../rustc_session" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
new file mode 100644 (file)
index 0000000..557e721
--- /dev/null
@@ -0,0 +1,238 @@
+//! Functions for reading and writing discriminants of multi-variant layouts (enums and generators).
+
+use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt};
+use rustc_middle::{mir, ty};
+use rustc_target::abi::{self, TagEncoding};
+use rustc_target::abi::{VariantIdx, Variants};
+
+use super::{ImmTy, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Scalar};
+
+impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
+    /// Writes the discriminant of the given variant.
+    #[instrument(skip(self), level = "trace")]
+    pub fn write_discriminant(
+        &mut self,
+        variant_index: VariantIdx,
+        dest: &PlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx> {
+        // Layout computation excludes uninhabited variants from consideration
+        // therefore there's no way to represent those variants in the given layout.
+        // Essentially, uninhabited variants do not have a tag that corresponds to their
+        // discriminant, so we cannot do anything here.
+        // When evaluating we will always error before even getting here, but ConstProp 'executes'
+        // dead code, so we cannot ICE here.
+        if dest.layout.for_variant(self, variant_index).abi.is_uninhabited() {
+            throw_ub!(UninhabitedEnumVariantWritten)
+        }
+
+        match dest.layout.variants {
+            abi::Variants::Single { index } => {
+                assert_eq!(index, variant_index);
+            }
+            abi::Variants::Multiple {
+                tag_encoding: TagEncoding::Direct,
+                tag: tag_layout,
+                tag_field,
+                ..
+            } => {
+                // No need to validate that the discriminant here because the
+                // `TyAndLayout::for_variant()` call earlier already checks the variant is valid.
+
+                let discr_val =
+                    dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val;
+
+                // raw discriminants for enums are isize or bigger during
+                // their computation, but the in-memory tag is the smallest possible
+                // representation
+                let size = tag_layout.size(self);
+                let tag_val = size.truncate(discr_val);
+
+                let tag_dest = self.place_field(dest, tag_field)?;
+                self.write_scalar(Scalar::from_uint(tag_val, size), &tag_dest)?;
+            }
+            abi::Variants::Multiple {
+                tag_encoding:
+                    TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start },
+                tag: tag_layout,
+                tag_field,
+                ..
+            } => {
+                // No need to validate that the discriminant here because the
+                // `TyAndLayout::for_variant()` call earlier already checks the variant is valid.
+
+                if variant_index != untagged_variant {
+                    let variants_start = niche_variants.start().as_u32();
+                    let variant_index_relative = variant_index
+                        .as_u32()
+                        .checked_sub(variants_start)
+                        .expect("overflow computing relative variant idx");
+                    // We need to use machine arithmetic when taking into account `niche_start`:
+                    // tag_val = variant_index_relative + niche_start_val
+                    let tag_layout = self.layout_of(tag_layout.primitive().to_int_ty(*self.tcx))?;
+                    let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
+                    let variant_index_relative_val =
+                        ImmTy::from_uint(variant_index_relative, tag_layout);
+                    let tag_val = self.binary_op(
+                        mir::BinOp::Add,
+                        &variant_index_relative_val,
+                        &niche_start_val,
+                    )?;
+                    // Write result.
+                    let niche_dest = self.place_field(dest, tag_field)?;
+                    self.write_immediate(*tag_val, &niche_dest)?;
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    /// Read discriminant, return the runtime value as well as the variant index.
+    /// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)!
+    #[instrument(skip(self), level = "trace")]
+    pub fn read_discriminant(
+        &self,
+        op: &OpTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, (Scalar<M::Provenance>, VariantIdx)> {
+        trace!("read_discriminant_value {:#?}", op.layout);
+        // Get type and layout of the discriminant.
+        let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
+        trace!("discriminant type: {:?}", discr_layout.ty);
+
+        // We use "discriminant" to refer to the value associated with a particular enum variant.
+        // This is not to be confused with its "variant index", which is just determining its position in the
+        // declared list of variants -- they can differ with explicitly assigned discriminants.
+        // We use "tag" to refer to how the discriminant is encoded in memory, which can be either
+        // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
+        let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants {
+            Variants::Single { index } => {
+                let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) {
+                    Some(discr) => {
+                        // This type actually has discriminants.
+                        assert_eq!(discr.ty, discr_layout.ty);
+                        Scalar::from_uint(discr.val, discr_layout.size)
+                    }
+                    None => {
+                        // On a type without actual discriminants, variant is 0.
+                        assert_eq!(index.as_u32(), 0);
+                        Scalar::from_uint(index.as_u32(), discr_layout.size)
+                    }
+                };
+                return Ok((discr, index));
+            }
+            Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => {
+                (tag, tag_encoding, tag_field)
+            }
+        };
+
+        // There are *three* layouts that come into play here:
+        // - The discriminant has a type for typechecking. This is `discr_layout`, and is used for
+        //   the `Scalar` we return.
+        // - The tag (encoded discriminant) has layout `tag_layout`. This is always an integer type,
+        //   and used to interpret the value we read from the tag field.
+        //   For the return value, a cast to `discr_layout` is performed.
+        // - The field storing the tag has a layout, which is very similar to `tag_layout` but
+        //   may be a pointer. This is `tag_val.layout`; we just use it for sanity checks.
+
+        // Get layout for tag.
+        let tag_layout = self.layout_of(tag_scalar_layout.primitive().to_int_ty(*self.tcx))?;
+
+        // Read tag and sanity-check `tag_layout`.
+        let tag_val = self.read_immediate(&self.operand_field(op, tag_field)?)?;
+        assert_eq!(tag_layout.size, tag_val.layout.size);
+        assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
+        trace!("tag value: {}", tag_val);
+
+        // Figure out which discriminant and variant this corresponds to.
+        Ok(match *tag_encoding {
+            TagEncoding::Direct => {
+                let scalar = tag_val.to_scalar();
+                // Generate a specific error if `tag_val` is not an integer.
+                // (`tag_bits` itself is only used for error messages below.)
+                let tag_bits = scalar
+                    .try_to_int()
+                    .map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))?
+                    .assert_bits(tag_layout.size);
+                // Cast bits from tag layout to discriminant layout.
+                // After the checks we did above, this cannot fail, as
+                // discriminants are int-like.
+                let discr_val =
+                    self.cast_from_int_like(scalar, tag_val.layout, discr_layout.ty).unwrap();
+                let discr_bits = discr_val.assert_bits(discr_layout.size);
+                // Convert discriminant to variant index, and catch invalid discriminants.
+                let index = match *op.layout.ty.kind() {
+                    ty::Adt(adt, _) => {
+                        adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits)
+                    }
+                    ty::Generator(def_id, substs, _) => {
+                        let substs = substs.as_generator();
+                        substs
+                            .discriminants(def_id, *self.tcx)
+                            .find(|(_, var)| var.val == discr_bits)
+                    }
+                    _ => span_bug!(self.cur_span(), "tagged layout for non-adt non-generator"),
+                }
+                .ok_or_else(|| err_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))))?;
+                // Return the cast value, and the index.
+                (discr_val, index.0)
+            }
+            TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
+                let tag_val = tag_val.to_scalar();
+                // Compute the variant this niche value/"tag" corresponds to. With niche layout,
+                // discriminant (encoded in niche/tag) and variant index are the same.
+                let variants_start = niche_variants.start().as_u32();
+                let variants_end = niche_variants.end().as_u32();
+                let variant = match tag_val.try_to_int() {
+                    Err(dbg_val) => {
+                        // So this is a pointer then, and casting to an int failed.
+                        // Can only happen during CTFE.
+                        // The niche must be just 0, and the ptr not null, then we know this is
+                        // okay. Everything else, we conservatively reject.
+                        let ptr_valid = niche_start == 0
+                            && variants_start == variants_end
+                            && !self.scalar_may_be_null(tag_val)?;
+                        if !ptr_valid {
+                            throw_ub!(InvalidTag(dbg_val))
+                        }
+                        untagged_variant
+                    }
+                    Ok(tag_bits) => {
+                        let tag_bits = tag_bits.assert_bits(tag_layout.size);
+                        // We need to use machine arithmetic to get the relative variant idx:
+                        // variant_index_relative = tag_val - niche_start_val
+                        let tag_val = ImmTy::from_uint(tag_bits, tag_layout);
+                        let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
+                        let variant_index_relative_val =
+                            self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?;
+                        let variant_index_relative =
+                            variant_index_relative_val.to_scalar().assert_bits(tag_val.layout.size);
+                        // Check if this is in the range that indicates an actual discriminant.
+                        if variant_index_relative <= u128::from(variants_end - variants_start) {
+                            let variant_index_relative = u32::try_from(variant_index_relative)
+                                .expect("we checked that this fits into a u32");
+                            // Then computing the absolute variant idx should not overflow any more.
+                            let variant_index = variants_start
+                                .checked_add(variant_index_relative)
+                                .expect("overflow computing absolute variant idx");
+                            let variants_len = op
+                                .layout
+                                .ty
+                                .ty_adt_def()
+                                .expect("tagged layout for non adt")
+                                .variants()
+                                .len();
+                            assert!(usize::try_from(variant_index).unwrap() < variants_len);
+                            VariantIdx::from_u32(variant_index)
+                        } else {
+                            untagged_variant
+                        }
+                    }
+                };
+                // Compute the size of the scalar we need to return.
+                // No need to cast, because the variant index directly serves as discriminant and is
+                // encoded in the tag.
+                (Scalar::from_uint(variant.as_u32(), discr_layout.size), variant)
+            }
+        })
+    }
+}
index 77c7b4bacb8c8a96d68b42704478166e754d0772..5042c6bac9932dcfd4821aa3e273c14fab373b7d 100644 (file)
@@ -78,13 +78,16 @@ pub(crate) fn alloc_caller_location(
         col: u32,
     ) -> MPlaceTy<'tcx, M::Provenance> {
         let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail;
+        // This can fail if rustc runs out of memory right here. Trying to emit an error would be
+        // pointless, since that would require allocating more memory than these short strings.
         let file = if loc_details.file {
             self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
+                .unwrap()
         } else {
             // FIXME: This creates a new allocation each time. It might be preferable to
             // perform this allocation only once, and re-use the `MPlaceTy`.
             // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
-            self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not)
+            self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not).unwrap()
         };
         let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
         let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
@@ -95,8 +98,6 @@ pub(crate) fn alloc_caller_location(
             .bound_type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
             .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter()));
         let loc_layout = self.layout_of(loc_ty).unwrap();
-        // This can fail if rustc runs out of memory right here. Trying to emit an error would be
-        // pointless, since that would require allocating more memory than a Location.
         let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
 
         // Initialize fields.
index 76ed7b80f8d81b7a69c553a2597450cd5710572a..d8087a36a7c6abfb48240319148c8e68e2bf3917 100644 (file)
@@ -291,7 +291,7 @@ fn extern_static_base_pointer(
     fn adjust_alloc_base_pointer(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         ptr: Pointer,
-    ) -> Pointer<Self::Provenance>;
+    ) -> InterpResult<'tcx, Pointer<Self::Provenance>>;
 
     /// "Int-to-pointer cast"
     fn ptr_from_addr_cast(
@@ -505,8 +505,8 @@ fn extern_static_base_pointer(
     fn adjust_alloc_base_pointer(
         _ecx: &InterpCx<$mir, $tcx, Self>,
         ptr: Pointer<AllocId>,
-    ) -> Pointer<AllocId> {
-        ptr
+    ) -> InterpResult<$tcx, Pointer<AllocId>> {
+        Ok(ptr)
     }
 
     #[inline(always)]
index a87ce0053e8a038932d7f71b711ce741094de771..cfad930b1e52ec6ca1174e7700b5e3135fbcdf80 100644 (file)
@@ -171,7 +171,7 @@ pub fn global_base_pointer(
             _ => {}
         }
         // And we need to get the provenance.
-        Ok(M::adjust_alloc_base_pointer(self, ptr))
+        M::adjust_alloc_base_pointer(self, ptr)
     }
 
     pub fn create_fn_alloc_ptr(
@@ -200,8 +200,7 @@ pub fn allocate_ptr(
         kind: MemoryKind<M::MemoryKind>,
     ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
         let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?;
-        // We can `unwrap` since `alloc` contains no pointers.
-        Ok(self.allocate_raw_ptr(alloc, kind).unwrap())
+        self.allocate_raw_ptr(alloc, kind)
     }
 
     pub fn allocate_bytes_ptr(
@@ -210,10 +209,9 @@ pub fn allocate_bytes_ptr(
         align: Align,
         kind: MemoryKind<M::MemoryKind>,
         mutability: Mutability,
-    ) -> Pointer<M::Provenance> {
+    ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
         let alloc = Allocation::from_bytes(bytes, align, mutability);
-        // We can `unwrap` since `alloc` contains no pointers.
-        self.allocate_raw_ptr(alloc, kind).unwrap()
+        self.allocate_raw_ptr(alloc, kind)
     }
 
     /// This can fail only of `alloc` contains provenance.
@@ -230,7 +228,7 @@ pub fn allocate_raw_ptr(
         );
         let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?;
         self.memory.alloc_map.insert(id, (kind, alloc.into_owned()));
-        Ok(M::adjust_alloc_base_pointer(self, Pointer::from(id)))
+        M::adjust_alloc_base_pointer(self, Pointer::from(id))
     }
 
     pub fn reallocate_ptr(
index 2e356f67bf36f70c273bad3fd8278cb99208bfc9..86de4e4e32c2a5961c1871f420a9c92859ef7d04 100644 (file)
@@ -1,6 +1,7 @@
 //! An interpreter for MIR used in CTFE and by miri
 
 mod cast;
+mod discriminant;
 mod eval_context;
 mod intern;
 mod intrinsics;
index a1b3985dce4e6ecfa27ff80b225e28e28f1d9d91..52613d5ca1f9b43c2ed532f398a368da5fabc6ea 100644 (file)
@@ -4,13 +4,12 @@
 use either::{Either, Left, Right};
 
 use rustc_hir::def::Namespace;
-use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
 use rustc_middle::ty::{ConstInt, Ty, ValTree};
 use rustc_middle::{mir, ty};
 use rustc_span::Span;
-use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size, TagEncoding};
-use rustc_target::abi::{VariantIdx, Variants};
+use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size};
 
 use super::{
     alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, GlobalId,
@@ -657,154 +656,6 @@ pub(super) fn const_val_to_op(
         };
         Ok(OpTy { op, layout, align: Some(layout.align.abi) })
     }
-
-    /// Read discriminant, return the runtime value as well as the variant index.
-    /// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)!
-    pub fn read_discriminant(
-        &self,
-        op: &OpTy<'tcx, M::Provenance>,
-    ) -> InterpResult<'tcx, (Scalar<M::Provenance>, VariantIdx)> {
-        trace!("read_discriminant_value {:#?}", op.layout);
-        // Get type and layout of the discriminant.
-        let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
-        trace!("discriminant type: {:?}", discr_layout.ty);
-
-        // We use "discriminant" to refer to the value associated with a particular enum variant.
-        // This is not to be confused with its "variant index", which is just determining its position in the
-        // declared list of variants -- they can differ with explicitly assigned discriminants.
-        // We use "tag" to refer to how the discriminant is encoded in memory, which can be either
-        // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
-        let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants {
-            Variants::Single { index } => {
-                let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) {
-                    Some(discr) => {
-                        // This type actually has discriminants.
-                        assert_eq!(discr.ty, discr_layout.ty);
-                        Scalar::from_uint(discr.val, discr_layout.size)
-                    }
-                    None => {
-                        // On a type without actual discriminants, variant is 0.
-                        assert_eq!(index.as_u32(), 0);
-                        Scalar::from_uint(index.as_u32(), discr_layout.size)
-                    }
-                };
-                return Ok((discr, index));
-            }
-            Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => {
-                (tag, tag_encoding, tag_field)
-            }
-        };
-
-        // There are *three* layouts that come into play here:
-        // - The discriminant has a type for typechecking. This is `discr_layout`, and is used for
-        //   the `Scalar` we return.
-        // - The tag (encoded discriminant) has layout `tag_layout`. This is always an integer type,
-        //   and used to interpret the value we read from the tag field.
-        //   For the return value, a cast to `discr_layout` is performed.
-        // - The field storing the tag has a layout, which is very similar to `tag_layout` but
-        //   may be a pointer. This is `tag_val.layout`; we just use it for sanity checks.
-
-        // Get layout for tag.
-        let tag_layout = self.layout_of(tag_scalar_layout.primitive().to_int_ty(*self.tcx))?;
-
-        // Read tag and sanity-check `tag_layout`.
-        let tag_val = self.read_immediate(&self.operand_field(op, tag_field)?)?;
-        assert_eq!(tag_layout.size, tag_val.layout.size);
-        assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
-        trace!("tag value: {}", tag_val);
-
-        // Figure out which discriminant and variant this corresponds to.
-        Ok(match *tag_encoding {
-            TagEncoding::Direct => {
-                let scalar = tag_val.to_scalar();
-                // Generate a specific error if `tag_val` is not an integer.
-                // (`tag_bits` itself is only used for error messages below.)
-                let tag_bits = scalar
-                    .try_to_int()
-                    .map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))?
-                    .assert_bits(tag_layout.size);
-                // Cast bits from tag layout to discriminant layout.
-                // After the checks we did above, this cannot fail, as
-                // discriminants are int-like.
-                let discr_val =
-                    self.cast_from_int_like(scalar, tag_val.layout, discr_layout.ty).unwrap();
-                let discr_bits = discr_val.assert_bits(discr_layout.size);
-                // Convert discriminant to variant index, and catch invalid discriminants.
-                let index = match *op.layout.ty.kind() {
-                    ty::Adt(adt, _) => {
-                        adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits)
-                    }
-                    ty::Generator(def_id, substs, _) => {
-                        let substs = substs.as_generator();
-                        substs
-                            .discriminants(def_id, *self.tcx)
-                            .find(|(_, var)| var.val == discr_bits)
-                    }
-                    _ => span_bug!(self.cur_span(), "tagged layout for non-adt non-generator"),
-                }
-                .ok_or_else(|| err_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))))?;
-                // Return the cast value, and the index.
-                (discr_val, index.0)
-            }
-            TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
-                let tag_val = tag_val.to_scalar();
-                // Compute the variant this niche value/"tag" corresponds to. With niche layout,
-                // discriminant (encoded in niche/tag) and variant index are the same.
-                let variants_start = niche_variants.start().as_u32();
-                let variants_end = niche_variants.end().as_u32();
-                let variant = match tag_val.try_to_int() {
-                    Err(dbg_val) => {
-                        // So this is a pointer then, and casting to an int failed.
-                        // Can only happen during CTFE.
-                        // The niche must be just 0, and the ptr not null, then we know this is
-                        // okay. Everything else, we conservatively reject.
-                        let ptr_valid = niche_start == 0
-                            && variants_start == variants_end
-                            && !self.scalar_may_be_null(tag_val)?;
-                        if !ptr_valid {
-                            throw_ub!(InvalidTag(dbg_val))
-                        }
-                        untagged_variant
-                    }
-                    Ok(tag_bits) => {
-                        let tag_bits = tag_bits.assert_bits(tag_layout.size);
-                        // We need to use machine arithmetic to get the relative variant idx:
-                        // variant_index_relative = tag_val - niche_start_val
-                        let tag_val = ImmTy::from_uint(tag_bits, tag_layout);
-                        let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
-                        let variant_index_relative_val =
-                            self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?;
-                        let variant_index_relative =
-                            variant_index_relative_val.to_scalar().assert_bits(tag_val.layout.size);
-                        // Check if this is in the range that indicates an actual discriminant.
-                        if variant_index_relative <= u128::from(variants_end - variants_start) {
-                            let variant_index_relative = u32::try_from(variant_index_relative)
-                                .expect("we checked that this fits into a u32");
-                            // Then computing the absolute variant idx should not overflow any more.
-                            let variant_index = variants_start
-                                .checked_add(variant_index_relative)
-                                .expect("overflow computing absolute variant idx");
-                            let variants_len = op
-                                .layout
-                                .ty
-                                .ty_adt_def()
-                                .expect("tagged layout for non adt")
-                                .variants()
-                                .len();
-                            assert!(usize::try_from(variant_index).unwrap() < variants_len);
-                            VariantIdx::from_u32(variant_index)
-                        } else {
-                            untagged_variant
-                        }
-                    }
-                };
-                // Compute the size of the scalar we need to return.
-                // No need to cast, because the variant index directly serves as discriminant and is
-                // encoded in the tag.
-                (Scalar::from_uint(variant.as_u32(), discr_layout.size), variant)
-            }
-        })
-    }
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
index 274af61ee7c1d5899b1d2d8b3a2700c912d9a0fa..038282e2161e6637891d2cde59fe2e766e40b189 100644 (file)
@@ -7,8 +7,8 @@
 use rustc_ast::Mutability;
 use rustc_middle::mir;
 use rustc_middle::ty;
-use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
-use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size, TagEncoding, VariantIdx};
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size, VariantIdx};
 
 use super::{
     alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckInAllocMsg,
@@ -754,8 +754,8 @@ pub fn allocate_str(
         str: &str,
         kind: MemoryKind<M::MemoryKind>,
         mutbl: Mutability,
-    ) -> MPlaceTy<'tcx, M::Provenance> {
-        let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl);
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
+        let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?;
         let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self);
         let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) };
 
@@ -764,95 +764,35 @@ pub fn allocate_str(
             ty::TypeAndMut { ty: self.tcx.types.str_, mutbl },
         );
         let layout = self.layout_of(ty).unwrap();
-        MPlaceTy { mplace, layout, align: layout.align.abi }
+        Ok(MPlaceTy { mplace, layout, align: layout.align.abi })
     }
 
-    /// Writes the discriminant of the given variant.
-    #[instrument(skip(self), level = "debug")]
-    pub fn write_discriminant(
+    /// Writes the aggregate to the destination.
+    #[instrument(skip(self), level = "trace")]
+    pub fn write_aggregate(
         &mut self,
-        variant_index: VariantIdx,
+        kind: &mir::AggregateKind<'tcx>,
+        operands: &[mir::Operand<'tcx>],
         dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
-        // This must be an enum or generator.
-        match dest.layout.ty.kind() {
-            ty::Adt(adt, _) => assert!(adt.is_enum()),
-            ty::Generator(..) => {}
-            _ => span_bug!(
-                self.cur_span(),
-                "write_discriminant called on non-variant-type (neither enum nor generator)"
-            ),
-        }
-        // Layout computation excludes uninhabited variants from consideration
-        // therefore there's no way to represent those variants in the given layout.
-        // Essentially, uninhabited variants do not have a tag that corresponds to their
-        // discriminant, so we cannot do anything here.
-        // When evaluating we will always error before even getting here, but ConstProp 'executes'
-        // dead code, so we cannot ICE here.
-        if dest.layout.for_variant(self, variant_index).abi.is_uninhabited() {
-            throw_ub!(UninhabitedEnumVariantWritten)
-        }
-
-        match dest.layout.variants {
-            abi::Variants::Single { index } => {
-                assert_eq!(index, variant_index);
-            }
-            abi::Variants::Multiple {
-                tag_encoding: TagEncoding::Direct,
-                tag: tag_layout,
-                tag_field,
-                ..
-            } => {
-                // No need to validate that the discriminant here because the
-                // `TyAndLayout::for_variant()` call earlier already checks the variant is valid.
-
-                let discr_val =
-                    dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val;
-
-                // raw discriminants for enums are isize or bigger during
-                // their computation, but the in-memory tag is the smallest possible
-                // representation
-                let size = tag_layout.size(self);
-                let tag_val = size.truncate(discr_val);
-
-                let tag_dest = self.place_field(dest, tag_field)?;
-                self.write_scalar(Scalar::from_uint(tag_val, size), &tag_dest)?;
-            }
-            abi::Variants::Multiple {
-                tag_encoding:
-                    TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start },
-                tag: tag_layout,
-                tag_field,
-                ..
-            } => {
-                // No need to validate that the discriminant here because the
-                // `TyAndLayout::for_variant()` call earlier already checks the variant is valid.
-
-                if variant_index != untagged_variant {
-                    let variants_start = niche_variants.start().as_u32();
-                    let variant_index_relative = variant_index
-                        .as_u32()
-                        .checked_sub(variants_start)
-                        .expect("overflow computing relative variant idx");
-                    // We need to use machine arithmetic when taking into account `niche_start`:
-                    // tag_val = variant_index_relative + niche_start_val
-                    let tag_layout = self.layout_of(tag_layout.primitive().to_int_ty(*self.tcx))?;
-                    let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
-                    let variant_index_relative_val =
-                        ImmTy::from_uint(variant_index_relative, tag_layout);
-                    let tag_val = self.binary_op(
-                        mir::BinOp::Add,
-                        &variant_index_relative_val,
-                        &niche_start_val,
-                    )?;
-                    // Write result.
-                    let niche_dest = self.place_field(dest, tag_field)?;
-                    self.write_immediate(*tag_val, &niche_dest)?;
-                }
+        self.write_uninit(&dest)?;
+        let (variant_index, variant_dest, active_field_index) = match *kind {
+            mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => {
+                let variant_dest = self.place_downcast(&dest, variant_index)?;
+                (variant_index, variant_dest, active_field_index)
             }
+            _ => (VariantIdx::from_u32(0), dest.clone(), None),
+        };
+        if active_field_index.is_some() {
+            assert_eq!(operands.len(), 1);
         }
-
-        Ok(())
+        for (field_index, operand) in operands.iter().enumerate() {
+            let field_index = active_field_index.unwrap_or(field_index);
+            let field_dest = self.place_field(&variant_dest, field_index)?;
+            let op = self.eval_operand(operand, Some(field_dest.layout))?;
+            self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?;
+        }
+        self.write_discriminant(variant_index, &dest)
     }
 
     pub fn raw_const_to_mplace(
index d101937fd7406cc64f214f60b0c1073024b87bc3..7d9a98da08a9a037ed104e5b55c9b4c49c524ef7 100644 (file)
@@ -199,13 +199,7 @@ pub fn eval_rvalue_into_place(
             }
 
             Aggregate(box ref kind, ref operands) => {
-                assert!(matches!(kind, mir::AggregateKind::Array(..)));
-
-                for (field_index, operand) in operands.iter().enumerate() {
-                    let op = self.eval_operand(operand, None)?;
-                    let field_dest = self.place_field(&dest, field_index)?;
-                    self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?;
-                }
+                self.write_aggregate(kind, operands, &dest)?;
             }
 
             Repeat(ref operand, _) => {
index f47e3e86ebe2e0a0eedf3b14903e62d986c2c341..1a23b06d2e89cae1296d78b618a6e10cf5d5de30 100644 (file)
@@ -453,7 +453,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
 
             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())
+                    && let Some(generator_kind @ hir::GeneratorKind::Async(..)) = self.tcx.generator_kind(def_id)
                 {
                     self.check_op(ops::Generator(generator_kind));
                 }
index 0cb5d2ff8c7193f21db958018b5732df9a26957c..3e416b89ca6ea5a417821cc3468ef09eb4155b57 100644 (file)
 use rustc_trait_selection::traits::SelectionContext;
 
 use super::ConstCx;
-use crate::errors::{
-    InteriorMutabilityBorrow, InteriorMutableDataRefer, MutDerefErr, NonConstFmtMacroCall,
-    NonConstFnCall, NonConstOpErr, PanicNonStrErr, RawPtrToIntErr, StaticAccessErr,
-    TransientMutBorrowErr, TransientMutBorrowErrRaw, UnallowedFnPointerCall,
-    UnallowedHeapAllocations, UnallowedInlineAsm, UnallowedMutableRefs, UnallowedMutableRefsRaw,
-    UnallowedOpInConstContext, UnstableConstFn,
-};
+use crate::errors;
 use crate::util::{call_kind, CallDesugaringKind, CallKind};
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -99,7 +93,7 @@ fn build_error(
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        ccx.tcx.sess.create_err(UnallowedFnPointerCall { span, kind: ccx.const_kind() })
+        ccx.tcx.sess.create_err(errors::UnallowedFnPointerCall { span, kind: ccx.const_kind() })
     }
 }
 
@@ -142,6 +136,7 @@ fn build_error(
                             &param_ty.name.as_str(),
                             &constraint,
                             None,
+                            None,
                         );
                     }
                 }
@@ -303,10 +298,11 @@ macro_rules! error {
                 diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span)));
                 err
             }
-            _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentV1Methods) => {
-                ccx.tcx.sess.create_err(NonConstFmtMacroCall { span, kind: ccx.const_kind() })
-            }
-            _ => ccx.tcx.sess.create_err(NonConstFnCall {
+            _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentV1Methods) => ccx
+                .tcx
+                .sess
+                .create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind() }),
+            _ => ccx.tcx.sess.create_err(errors::NonConstFnCall {
                 span,
                 def_path_str: ccx.tcx.def_path_str_with_substs(callee, substs),
                 kind: ccx.const_kind(),
@@ -351,7 +347,7 @@ fn build_error(
         let mut err = ccx
             .tcx
             .sess
-            .create_err(UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) });
+            .create_err(errors::UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) });
 
         if ccx.is_const_stable_const_fn() {
             err.help("const-stable functions can only call other const-stable functions");
@@ -387,11 +383,11 @@ fn build_error(
         let msg = format!("{}s are not allowed in {}s", self.0.descr(), ccx.const_kind());
         if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
             ccx.tcx.sess.create_feature_err(
-                UnallowedOpInConstContext { span, msg },
+                errors::UnallowedOpInConstContext { span, msg },
                 sym::const_async_blocks,
             )
         } else {
-            ccx.tcx.sess.create_err(UnallowedOpInConstContext { span, msg })
+            ccx.tcx.sess.create_err(errors::UnallowedOpInConstContext { span, msg })
         }
     }
 }
@@ -404,7 +400,7 @@ fn build_error(
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        ccx.tcx.sess.create_err(UnallowedHeapAllocations {
+        ccx.tcx.sess.create_err(errors::UnallowedHeapAllocations {
             span,
             kind: ccx.const_kind(),
             teach: ccx.tcx.sess.teach(&error_code!(E0010)).then_some(()),
@@ -420,7 +416,7 @@ fn build_error(
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        ccx.tcx.sess.create_err(UnallowedInlineAsm { span, kind: ccx.const_kind() })
+        ccx.tcx.sess.create_err(errors::UnallowedInlineAsm { span, kind: ccx.const_kind() })
     }
 }
 
@@ -471,7 +467,9 @@ fn build_error(
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        ccx.tcx.sess.create_feature_err(InteriorMutabilityBorrow { span }, sym::const_refs_to_cell)
+        ccx.tcx
+            .sess
+            .create_feature_err(errors::InteriorMutabilityBorrow { span }, sym::const_refs_to_cell)
     }
 }
 
@@ -488,14 +486,14 @@ fn build_error(
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         // FIXME: Maybe a more elegant solution to this if else case
         if let hir::ConstContext::Static(_) = ccx.const_kind() {
-            ccx.tcx.sess.create_err(InteriorMutableDataRefer {
+            ccx.tcx.sess.create_err(errors::InteriorMutableDataRefer {
                 span,
                 opt_help: Some(()),
                 kind: ccx.const_kind(),
                 teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()),
             })
         } else {
-            ccx.tcx.sess.create_err(InteriorMutableDataRefer {
+            ccx.tcx.sess.create_err(errors::InteriorMutableDataRefer {
                 span,
                 opt_help: None,
                 kind: ccx.const_kind(),
@@ -528,12 +526,12 @@ fn build_error(
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         match self.0 {
-            hir::BorrowKind::Raw => ccx.tcx.sess.create_err(UnallowedMutableRefsRaw {
+            hir::BorrowKind::Raw => ccx.tcx.sess.create_err(errors::UnallowedMutableRefsRaw {
                 span,
                 kind: ccx.const_kind(),
                 teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()),
             }),
-            hir::BorrowKind::Ref => ccx.tcx.sess.create_err(UnallowedMutableRefs {
+            hir::BorrowKind::Ref => ccx.tcx.sess.create_err(errors::UnallowedMutableRefs {
                 span,
                 kind: ccx.const_kind(),
                 teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()),
@@ -557,14 +555,14 @@ fn build_error(
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let kind = ccx.const_kind();
         match self.0 {
-            hir::BorrowKind::Raw => ccx
-                .tcx
-                .sess
-                .create_feature_err(TransientMutBorrowErrRaw { span, kind }, sym::const_mut_refs),
-            hir::BorrowKind::Ref => ccx
-                .tcx
-                .sess
-                .create_feature_err(TransientMutBorrowErr { span, kind }, sym::const_mut_refs),
+            hir::BorrowKind::Raw => ccx.tcx.sess.create_feature_err(
+                errors::TransientMutBorrowErrRaw { span, kind },
+                sym::const_mut_refs,
+            ),
+            hir::BorrowKind::Ref => ccx.tcx.sess.create_feature_err(
+                errors::TransientMutBorrowErr { span, kind },
+                sym::const_mut_refs,
+            ),
         }
     }
 }
@@ -586,9 +584,10 @@ fn build_error(
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        ccx.tcx
-            .sess
-            .create_feature_err(MutDerefErr { span, kind: ccx.const_kind() }, sym::const_mut_refs)
+        ccx.tcx.sess.create_feature_err(
+            errors::MutDerefErr { span, kind: ccx.const_kind() },
+            sym::const_mut_refs,
+        )
     }
 }
 
@@ -601,7 +600,7 @@ fn build_error(
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        ccx.tcx.sess.create_err(PanicNonStrErr { span })
+        ccx.tcx.sess.create_err(errors::PanicNonStrErr { span })
     }
 }
 
@@ -652,7 +651,7 @@ fn build_error(
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        ccx.tcx.sess.create_err(RawPtrToIntErr { span })
+        ccx.tcx.sess.create_err(errors::RawPtrToIntErr { span })
     }
 }
 
@@ -673,7 +672,7 @@ fn build_error(
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        ccx.tcx.sess.create_err(StaticAccessErr {
+        ccx.tcx.sess.create_err(errors::StaticAccessErr {
             span,
             kind: ccx.const_kind(),
             teach: ccx.tcx.sess.teach(&error_code!(E0013)).then_some(()),
@@ -690,7 +689,7 @@ fn build_error(
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        ccx.tcx.sess.create_err(NonConstOpErr { span })
+        ccx.tcx.sess.create_err(errors::NonConstOpErr { span })
     }
 }
 
index 72f456138ef56c63e38652be3bf18a4d105b53f5..76b316cdf0c3fdecc5ccc061b251f3c8b878a96e 100644 (file)
@@ -8,10 +8,10 @@
 use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
-    traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping,
-    Local, Location, MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef,
-    ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
-    Terminator, TerminatorKind, UnOp, START_BLOCK,
+    traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
+    MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem,
+    RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
+    TerminatorKind, UnOp, START_BLOCK,
 };
 use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt};
 use rustc_mir_dataflow::impls::MaybeStorageLive;
@@ -423,19 +423,7 @@ macro_rules! check_kinds {
             };
         }
         match rvalue {
-            Rvalue::Use(_) | Rvalue::CopyForDeref(_) => {}
-            Rvalue::Aggregate(agg_kind, _) => {
-                let disallowed = match **agg_kind {
-                    AggregateKind::Array(..) => false,
-                    _ => self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup),
-                };
-                if disallowed {
-                    self.fail(
-                        location,
-                        format!("{:?} have been lowered to field assignments", rvalue),
-                    )
-                }
-            }
+            Rvalue::Use(_) | Rvalue::CopyForDeref(_) | Rvalue::Aggregate(..) => {}
             Rvalue::Ref(_, BorrowKind::Shallow, _) => {
                 if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
                     self.fail(
diff --git a/compiler/rustc_const_eval/src/util/aggregate.rs b/compiler/rustc_const_eval/src/util/aggregate.rs
deleted file mode 100644 (file)
index 10783c5..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-use rustc_index::vec::Idx;
-use rustc_middle::mir::*;
-use rustc_middle::ty::{Ty, TyCtxt};
-use rustc_target::abi::VariantIdx;
-
-use std::iter::TrustedLen;
-
-/// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields.
-///
-/// Produces something like
-/// ```ignore (ilustrative)
-/// (lhs as Variant).field0 = arg0;     // We only have a downcast if this is an enum
-/// (lhs as Variant).field1 = arg1;
-/// discriminant(lhs) = variant_index;  // If lhs is an enum or generator.
-/// ```
-pub fn expand_aggregate<'tcx>(
-    orig_lhs: Place<'tcx>,
-    operands: impl Iterator<Item = (Operand<'tcx>, Ty<'tcx>)> + TrustedLen,
-    kind: AggregateKind<'tcx>,
-    source_info: SourceInfo,
-    tcx: TyCtxt<'tcx>,
-) -> impl Iterator<Item = Statement<'tcx>> + TrustedLen {
-    let mut lhs = orig_lhs;
-    let mut set_discriminant = None;
-    let active_field_index = match kind {
-        AggregateKind::Adt(adt_did, variant_index, _, _, active_field_index) => {
-            let adt_def = tcx.adt_def(adt_did);
-            if adt_def.is_enum() {
-                set_discriminant = Some(Statement {
-                    kind: StatementKind::SetDiscriminant {
-                        place: Box::new(orig_lhs),
-                        variant_index,
-                    },
-                    source_info,
-                });
-                lhs = tcx.mk_place_downcast(orig_lhs, adt_def, variant_index);
-            }
-            active_field_index
-        }
-        AggregateKind::Generator(..) => {
-            // Right now we only support initializing generators to
-            // variant 0 (Unresumed).
-            let variant_index = VariantIdx::new(0);
-            set_discriminant = Some(Statement {
-                kind: StatementKind::SetDiscriminant { place: Box::new(orig_lhs), variant_index },
-                source_info,
-            });
-
-            // Operands are upvars stored on the base place, so no
-            // downcast is necessary.
-
-            None
-        }
-        _ => None,
-    };
-
-    let operands = operands.enumerate().map(move |(i, (op, ty))| {
-        let lhs_field = if let AggregateKind::Array(_) = kind {
-            let offset = u64::try_from(i).unwrap();
-            tcx.mk_place_elem(
-                lhs,
-                ProjectionElem::ConstantIndex { offset, min_length: offset + 1, from_end: false },
-            )
-        } else {
-            let field = Field::new(active_field_index.unwrap_or(i));
-            tcx.mk_place_field(lhs, field, ty)
-        };
-        Statement {
-            source_info,
-            kind: StatementKind::Assign(Box::new((lhs_field, Rvalue::Use(op)))),
-        }
-    });
-    [Statement { source_info, kind: StatementKind::Deinit(Box::new(orig_lhs)) }]
-        .into_iter()
-        .chain(operands)
-        .chain(set_discriminant)
-}
index 76ea5a24e69edd8c1bd09cab7ece7e05eb345302..51735e33e0f7142c9536a9aec475ce764712ffd1 100644 (file)
@@ -1,4 +1,3 @@
-pub mod aggregate;
 mod alignment;
 mod call_kind;
 pub mod collect_writes;
@@ -7,7 +6,6 @@
 mod might_permit_raw_init;
 mod type_name;
 
-pub use self::aggregate::expand_aggregate;
 pub use self::alignment::is_disaligned;
 pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
 pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype};
index 59e937777483ec1941854b6d66d5b29c26ea4a49..d7c295418ba6d6d04688b046d494d9b12880b8c4 100644 (file)
@@ -7,39 +7,4 @@ edition = "2021"
 crate-type = ["dylib"]
 
 [dependencies]
-tracing = { version = "0.1.35" }
-serde_json = "1.0.59"
-rustc_log = { path = "../rustc_log" }
-rustc_middle = { path = "../rustc_middle" }
-rustc_ast_pretty = { path = "../rustc_ast_pretty" }
-rustc_target = { path = "../rustc_target" }
-rustc_lint = { path = "../rustc_lint" }
-rustc_data_structures = { path = "../rustc_data_structures" }
-rustc_errors = { path = "../rustc_errors" }
-rustc_feature = { path = "../rustc_feature" }
-rustc_hir = { path = "../rustc_hir" }
-rustc_hir_pretty = { path = "../rustc_hir_pretty" }
-rustc_macros = { path = "../rustc_macros" }
-rustc_metadata = { path = "../rustc_metadata" }
-rustc_parse = { path = "../rustc_parse" }
-rustc_plugin_impl = { path = "../rustc_plugin_impl" }
-rustc_save_analysis = { path = "../rustc_save_analysis" }
-rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
-rustc_session = { path = "../rustc_session" }
-rustc_error_codes = { path = "../rustc_error_codes" }
-rustc_interface = { path = "../rustc_interface" }
-rustc_ast = { path = "../rustc_ast" }
-rustc_span = { path = "../rustc_span" }
-rustc_hir_analysis = { path = "../rustc_hir_analysis" }
-
-[target.'cfg(unix)'.dependencies]
-libc = "0.2"
-
-[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] }
-
-[features]
-llvm = ['rustc_interface/llvm']
-max_level_info = ['rustc_log/max_level_info']
-rustc_use_parallel_compiler = ['rustc_data_structures/rustc_use_parallel_compiler', 'rustc_interface/rustc_use_parallel_compiler',
-    'rustc_middle/rustc_use_parallel_compiler']
+rustc_driver_impl = { path = "../rustc_driver_impl" }
diff --git a/compiler/rustc_driver/README.md b/compiler/rustc_driver/README.md
deleted file mode 100644 (file)
index 6d7fba3..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-The `driver` crate is effectively the "main" function for the rust
-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
-options).
-
-For more information about how the driver works, see the [rustc dev guide].
-
-[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/rustc-driver.html
diff --git a/compiler/rustc_driver/src/args.rs b/compiler/rustc_driver/src/args.rs
deleted file mode 100644 (file)
index 42c97cc..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-use std::error;
-use std::fmt;
-use std::fs;
-use std::io;
-
-fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
-    if let Some(path) = arg.strip_prefix('@') {
-        let file = match fs::read_to_string(path) {
-            Ok(file) => file,
-            Err(ref err) if err.kind() == io::ErrorKind::InvalidData => {
-                return Err(Error::Utf8Error(Some(path.to_string())));
-            }
-            Err(err) => return Err(Error::IOError(path.to_string(), err)),
-        };
-        Ok(file.lines().map(ToString::to_string).collect())
-    } else {
-        Ok(vec![arg])
-    }
-}
-
-pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
-    let mut args = Vec::new();
-    for arg in at_args {
-        match arg_expand(arg.clone()) {
-            Ok(arg) => args.extend(arg),
-            Err(err) => rustc_session::early_error(
-                rustc_session::config::ErrorOutputType::default(),
-                &format!("Failed to load argument file: {err}"),
-            ),
-        }
-    }
-    args
-}
-
-#[derive(Debug)]
-pub enum Error {
-    Utf8Error(Option<String>),
-    IOError(String, io::Error),
-}
-
-impl fmt::Display for Error {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Error::Utf8Error(None) => write!(fmt, "Utf8 error"),
-            Error::Utf8Error(Some(path)) => write!(fmt, "Utf8 error in {path}"),
-            Error::IOError(path, err) => write!(fmt, "IO Error: {path}: {err}"),
-        }
-    }
-}
-
-impl error::Error for Error {}
index 02e0b042ad2631eadad94771b4a2dfab2c2defd4..4eabba575f42a425ef264e2d177e9178c9848af7 100644 (file)
-//! The Rust compiler.
-//!
-//! # Note
-//!
-//! This API is completely unstable and subject to change.
+// This crate is intentionally empty and a rexport of `rustc_driver_impl` to allow the code in
+// `rustc_driver_impl` to be compiled in parallel with other crates.
 
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(is_terminal)]
-#![feature(once_cell)]
-#![feature(decl_macro)]
-#![recursion_limit = "256"]
-#![allow(rustc::potential_query_instability)]
-#![deny(rustc::untranslatable_diagnostic)]
-#![deny(rustc::diagnostic_outside_of_impl)]
-
-#[macro_use]
-extern crate tracing;
-
-pub extern crate rustc_plugin_impl as plugin;
-
-use rustc_ast as ast;
-use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults};
-use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
-use rustc_data_structures::sync::SeqCst;
-use rustc_errors::registry::{InvalidErrorCode, Registry};
-use rustc_errors::{ErrorGuaranteed, PResult};
-use rustc_feature::find_gated_cfg;
-use rustc_hir::def_id::LOCAL_CRATE;
-use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
-use rustc_interface::{interface, Queries};
-use rustc_lint::LintStore;
-use rustc_metadata::locator;
-use rustc_save_analysis as save;
-use rustc_save_analysis::DumpHandler;
-use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
-use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
-use rustc_session::cstore::MetadataLoader;
-use rustc_session::getopts;
-use rustc_session::lint::{Lint, LintId};
-use rustc_session::{config, Session};
-use rustc_session::{early_error, early_error_no_abort, early_warn};
-use rustc_span::source_map::{FileLoader, FileName};
-use rustc_span::symbol::sym;
-use rustc_target::json::ToJson;
-
-use std::cmp::max;
-use std::env;
-use std::ffi::OsString;
-use std::fs;
-use std::io::{self, IsTerminal, Read, Write};
-use std::panic::{self, catch_unwind};
-use std::path::PathBuf;
-use std::process::{self, Command, Stdio};
-use std::str;
-use std::sync::LazyLock;
-use std::time::Instant;
-
-pub mod args;
-pub mod pretty;
-mod session_diagnostics;
-
-use crate::session_diagnostics::{
-    RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch,
-    RLinkWrongFileType, RlinkNotAFile, RlinkUnableToRead,
-};
-
-/// Exit status code used for successful compilation and help output.
-pub const EXIT_SUCCESS: i32 = 0;
-
-/// Exit status code used for compilation failures and invalid flags.
-pub const EXIT_FAILURE: i32 = 1;
-
-const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
-    ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
-
-const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["-Z", "-C", "--crate-type"];
-
-const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename"];
-
-const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &[&str] = &["incremental"];
-
-pub fn abort_on_err<T>(result: Result<T, ErrorGuaranteed>, sess: &Session) -> T {
-    match result {
-        Err(..) => {
-            sess.abort_if_errors();
-            panic!("error reported but abort_if_errors didn't abort???");
-        }
-        Ok(x) => x,
-    }
-}
-
-pub trait Callbacks {
-    /// Called before creating the compiler instance
-    fn config(&mut self, _config: &mut interface::Config) {}
-    /// Called after parsing. Return value instructs the compiler whether to
-    /// continue the compilation afterwards (defaults to `Compilation::Continue`)
-    fn after_parsing<'tcx>(
-        &mut self,
-        _compiler: &interface::Compiler,
-        _queries: &'tcx Queries<'tcx>,
-    ) -> Compilation {
-        Compilation::Continue
-    }
-    /// Called after expansion. Return value instructs the compiler whether to
-    /// continue the compilation afterwards (defaults to `Compilation::Continue`)
-    fn after_expansion<'tcx>(
-        &mut self,
-        _compiler: &interface::Compiler,
-        _queries: &'tcx Queries<'tcx>,
-    ) -> Compilation {
-        Compilation::Continue
-    }
-    /// Called after analysis. Return value instructs the compiler whether to
-    /// continue the compilation afterwards (defaults to `Compilation::Continue`)
-    fn after_analysis<'tcx>(
-        &mut self,
-        _compiler: &interface::Compiler,
-        _queries: &'tcx Queries<'tcx>,
-    ) -> Compilation {
-        Compilation::Continue
-    }
-}
-
-#[derive(Default)]
-pub struct TimePassesCallbacks {
-    time_passes: bool,
-}
-
-impl Callbacks for TimePassesCallbacks {
-    // JUSTIFICATION: the session doesn't exist at this point.
-    #[allow(rustc::bad_opt_access)]
-    fn config(&mut self, config: &mut interface::Config) {
-        // If a --print=... option has been given, we don't print the "total"
-        // time because it will mess up the --print output. See #64339.
-        //
-        self.time_passes = config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes;
-        config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath;
-    }
-}
-
-pub fn diagnostics_registry() -> Registry {
-    Registry::new(rustc_error_codes::DIAGNOSTICS)
-}
-
-/// This is the primary entry point for rustc.
-pub struct RunCompiler<'a, 'b> {
-    at_args: &'a [String],
-    callbacks: &'b mut (dyn Callbacks + Send),
-    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    make_codegen_backend:
-        Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
-}
-
-impl<'a, 'b> RunCompiler<'a, 'b> {
-    pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self {
-        Self { at_args, callbacks, file_loader: None, make_codegen_backend: None }
-    }
-
-    /// Set a custom codegen backend.
-    ///
-    /// Has no uses within this repository, but is used by bjorn3 for "the
-    /// hotswapping branch of cg_clif" for "setting the codegen backend from a
-    /// custom driver where the custom codegen backend has arbitrary data."
-    /// (See #102759.)
-    pub fn set_make_codegen_backend(
-        &mut self,
-        make_codegen_backend: Option<
-            Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
-        >,
-    ) -> &mut Self {
-        self.make_codegen_backend = make_codegen_backend;
-        self
-    }
-
-    /// Load files from sources other than the file system.
-    ///
-    /// Has no uses within this repository, but may be used in the future by
-    /// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for
-    /// running rustc without having to save". (See #102759.)
-    pub fn set_file_loader(
-        &mut self,
-        file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    ) -> &mut Self {
-        self.file_loader = file_loader;
-        self
-    }
-
-    /// Parse args and run the compiler.
-    pub fn run(self) -> interface::Result<()> {
-        run_compiler(self.at_args, self.callbacks, self.file_loader, self.make_codegen_backend)
-    }
-}
-
-fn run_compiler(
-    at_args: &[String],
-    callbacks: &mut (dyn Callbacks + Send),
-    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    make_codegen_backend: Option<
-        Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
-    >,
-) -> interface::Result<()> {
-    let args = args::arg_expand_all(at_args);
-
-    let Some(matches) = handle_options(&args) else { return Ok(()) };
-
-    let sopts = config::build_session_options(&matches);
-
-    if let Some(ref code) = matches.opt_str("explain") {
-        handle_explain(diagnostics_registry(), code, sopts.error_format);
-        return Ok(());
-    }
-
-    let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
-    let check_cfg = interface::parse_check_cfg(matches.opt_strs("check-cfg"));
-    let (odir, ofile) = make_output(&matches);
-    let mut config = interface::Config {
-        opts: sopts,
-        crate_cfg: cfg,
-        crate_check_cfg: check_cfg,
-        input: Input::File(PathBuf::new()),
-        output_file: ofile,
-        output_dir: odir,
-        file_loader,
-        lint_caps: Default::default(),
-        parse_sess_created: None,
-        register_lints: None,
-        override_queries: None,
-        make_codegen_backend,
-        registry: diagnostics_registry(),
-    };
-
-    if !tracing::dispatcher::has_been_set() {
-        init_rustc_env_logger_with_backtrace_option(&config.opts.unstable_opts.log_backtrace);
-    }
-
-    match make_input(config.opts.error_format, &matches.free) {
-        Err(reported) => return Err(reported),
-        Ok(Some(input)) => {
-            config.input = input;
-
-            callbacks.config(&mut config);
-        }
-        Ok(None) => match matches.free.len() {
-            0 => {
-                callbacks.config(&mut config);
-                interface::run_compiler(config, |compiler| {
-                    let sopts = &compiler.session().opts;
-                    if sopts.describe_lints {
-                        let mut lint_store =
-                            rustc_lint::new_lint_store(compiler.session().enable_internal_lints());
-                        let registered_lints =
-                            if let Some(register_lints) = compiler.register_lints() {
-                                register_lints(compiler.session(), &mut lint_store);
-                                true
-                            } else {
-                                false
-                            };
-                        describe_lints(compiler.session(), &lint_store, registered_lints);
-                        return;
-                    }
-                    let should_stop =
-                        print_crate_info(&***compiler.codegen_backend(), compiler.session(), false);
-
-                    if should_stop == Compilation::Stop {
-                        return;
-                    }
-                    early_error(sopts.error_format, "no input filename given")
-                });
-                return Ok(());
-            }
-            1 => panic!("make_input should have provided valid inputs"),
-            _ => early_error(
-                config.opts.error_format,
-                &format!(
-                    "multiple input filenames provided (first two filenames are `{}` and `{}`)",
-                    matches.free[0], matches.free[1],
-                ),
-            ),
-        },
-    };
-
-    interface::run_compiler(config, |compiler| {
-        let sess = compiler.session();
-        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();
-        }
-
-        let linker = compiler.enter(|queries| {
-            let early_exit = || sess.compile_status().map(|_| None);
-            queries.parse()?;
-
-            if let Some(ppm) = &sess.opts.pretty {
-                if ppm.needs_ast_map() {
-                    queries.global_ctxt()?.enter(|tcx| {
-                        pretty::print_after_hir_lowering(tcx, *ppm);
-                        Ok(())
-                    })?;
-                } else {
-                    let krate = queries.parse()?.steal();
-                    pretty::print_after_parsing(sess, &krate, *ppm);
-                }
-                trace!("finished pretty-printing");
-                return early_exit();
-            }
-
-            if callbacks.after_parsing(compiler, queries) == Compilation::Stop {
-                return early_exit();
-            }
-
-            if sess.opts.unstable_opts.parse_only || sess.opts.unstable_opts.show_span.is_some() {
-                return early_exit();
-            }
-
-            {
-                let plugins = queries.register_plugins()?;
-                let (_, lint_store) = &*plugins.borrow();
-
-                // Lint plugins are registered; now we can process command line flags.
-                if sess.opts.describe_lints {
-                    describe_lints(sess, lint_store, true);
-                    return early_exit();
-                }
-            }
-
-            let mut gctxt = queries.global_ctxt()?;
-            if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
-                return early_exit();
-            }
-
-            // Make sure the `output_filenames` query is run for its side
-            // effects of writing the dep-info and reporting errors.
-            gctxt.enter(|tcx| tcx.output_filenames(()));
-
-            if sess.opts.output_types.contains_key(&OutputType::DepInfo)
-                && sess.opts.output_types.len() == 1
-            {
-                return early_exit();
-            }
-
-            if sess.opts.unstable_opts.no_analysis {
-                return early_exit();
-            }
-
-            gctxt.enter(|tcx| {
-                let result = tcx.analysis(());
-                if sess.opts.unstable_opts.save_analysis {
-                    let crate_name = tcx.crate_name(LOCAL_CRATE);
-                    sess.time("save_analysis", || {
-                        save::process_crate(
-                            tcx,
-                            crate_name,
-                            &sess.io.input,
-                            None,
-                            DumpHandler::new(sess.io.output_dir.as_deref(), crate_name),
-                        )
-                    });
-                }
-                result
-            })?;
-
-            drop(gctxt);
-
-            if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
-                return early_exit();
-            }
-
-            queries.ongoing_codegen()?;
-
-            if sess.opts.unstable_opts.print_type_sizes {
-                sess.code_stats.print_type_sizes();
-            }
-
-            let linker = queries.linker()?;
-            Ok(Some(linker))
-        })?;
-
-        if let Some(linker) = linker {
-            let _timer = sess.timer("link");
-            linker.link()?
-        }
-
-        if sess.opts.unstable_opts.perf_stats {
-            sess.print_perf_stats();
-        }
-
-        if sess.opts.unstable_opts.print_fuel.is_some() {
-            eprintln!(
-                "Fuel used by {}: {}",
-                sess.opts.unstable_opts.print_fuel.as_ref().unwrap(),
-                sess.print_fuel.load(SeqCst)
-            );
-        }
-
-        Ok(())
-    })
-}
-
-// Extract output directory and file from matches.
-fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
-    let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
-    let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o));
-    (odir, ofile)
-}
-
-// Extract input (string or file and optional path) from matches.
-fn make_input(
-    error_format: ErrorOutputType,
-    free_matches: &[String],
-) -> Result<Option<Input>, ErrorGuaranteed> {
-    if free_matches.len() == 1 {
-        let ifile = &free_matches[0];
-        if ifile == "-" {
-            let mut src = String::new();
-            if io::stdin().read_to_string(&mut src).is_err() {
-                // Immediately stop compilation if there was an issue reading
-                // the input (for example if the input stream is not UTF-8).
-                let reported = early_error_no_abort(
-                    error_format,
-                    "couldn't read from stdin, as it did not contain valid UTF-8",
-                );
-                return Err(reported);
-            }
-            if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
-                let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
-                    "when UNSTABLE_RUSTDOC_TEST_PATH is set \
-                                    UNSTABLE_RUSTDOC_TEST_LINE also needs to be set",
-                );
-                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 }))
-            } else {
-                Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src }))
-            }
-        } else {
-            Ok(Some(Input::File(PathBuf::from(ifile))))
-        }
-    } else {
-        Ok(None)
-    }
-}
-
-/// Whether to stop or continue compilation.
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub enum Compilation {
-    Stop,
-    Continue,
-}
-
-impl Compilation {
-    pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
-        match self {
-            Compilation::Stop => Compilation::Stop,
-            Compilation::Continue => next(),
-        }
-    }
-}
-
-fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
-    let upper_cased_code = code.to_ascii_uppercase();
-    let normalised =
-        if upper_cased_code.starts_with('E') { upper_cased_code } else { format!("E{code:0>4}") };
-    match registry.try_find_description(&normalised) {
-        Ok(Some(description)) => {
-            let mut is_in_code_block = false;
-            let mut text = String::new();
-            // Slice off the leading newline and print.
-            for line in description.lines() {
-                let indent_level =
-                    line.find(|c: char| !c.is_whitespace()).unwrap_or_else(|| line.len());
-                let dedented_line = &line[indent_level..];
-                if dedented_line.starts_with("```") {
-                    is_in_code_block = !is_in_code_block;
-                    text.push_str(&line[..(indent_level + 3)]);
-                } else if is_in_code_block && dedented_line.starts_with("# ") {
-                    continue;
-                } else {
-                    text.push_str(line);
-                }
-                text.push('\n');
-            }
-            if io::stdout().is_terminal() {
-                show_content_with_pager(&text);
-            } else {
-                print!("{text}");
-            }
-        }
-        Ok(None) => {
-            early_error(output, &format!("no extended information for {code}"));
-        }
-        Err(InvalidErrorCode) => {
-            early_error(output, &format!("{code} is not a valid error code"));
-        }
-    }
-}
-
-fn show_content_with_pager(content: &str) {
-    let pager_name = env::var_os("PAGER").unwrap_or_else(|| {
-        if cfg!(windows) { OsString::from("more.com") } else { OsString::from("less") }
-    });
-
-    let mut fallback_to_println = false;
-
-    match Command::new(pager_name).stdin(Stdio::piped()).spawn() {
-        Ok(mut pager) => {
-            if let Some(pipe) = pager.stdin.as_mut() {
-                if pipe.write_all(content.as_bytes()).is_err() {
-                    fallback_to_println = true;
-                }
-            }
-
-            if pager.wait().is_err() {
-                fallback_to_println = true;
-            }
-        }
-        Err(_) => {
-            fallback_to_println = true;
-        }
-    }
-
-    // If pager fails for whatever reason, we should still print the content
-    // to standard output
-    if fallback_to_println {
-        print!("{content}");
-    }
-}
-
-pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
-    if sess.opts.unstable_opts.link_only {
-        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, &[]);
-            let rlink_data = fs::read(file).unwrap_or_else(|err| {
-                sess.emit_fatal(RlinkUnableToRead { err });
-            });
-            let codegen_results = match CodegenResults::deserialize_rlink(rlink_data) {
-                Ok(codegen) => codegen,
-                Err(err) => {
-                    match err {
-                        CodegenErrors::WrongFileType => sess.emit_fatal(RLinkWrongFileType),
-                        CodegenErrors::EmptyVersionNumber => {
-                            sess.emit_fatal(RLinkEmptyVersionNumber)
-                        }
-                        CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => {
-                            sess.emit_fatal(RLinkEncodingVersionMismatch {
-                                version_array,
-                                rlink_version,
-                            })
-                        }
-                        CodegenErrors::RustcVersionMismatch { rustc_version, current_version } => {
-                            sess.emit_fatal(RLinkRustcVersionMismatch {
-                                rustc_version,
-                                current_version,
-                            })
-                        }
-                    };
-                }
-            };
-            let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
-            abort_on_err(result, sess);
-        } else {
-            sess.emit_fatal(RlinkNotAFile {})
-        }
-        Compilation::Stop
-    } else {
-        Compilation::Continue
-    }
-}
-
-pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Compilation {
-    if sess.opts.unstable_opts.ls {
-        match sess.io.input {
-            Input::File(ref ifile) => {
-                let path = &(*ifile);
-                let mut v = Vec::new();
-                locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v).unwrap();
-                println!("{}", String::from_utf8(v).unwrap());
-            }
-            Input::Str { .. } => {
-                early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
-            }
-        }
-        return Compilation::Stop;
-    }
-
-    Compilation::Continue
-}
-
-fn print_crate_info(
-    codegen_backend: &dyn CodegenBackend,
-    sess: &Session,
-    parse_attrs: bool,
-) -> Compilation {
-    use rustc_session::config::PrintRequest::*;
-    // NativeStaticLibs and LinkArgs are special - printed during linking
-    // (empty iterator returns true)
-    if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) {
-        return Compilation::Continue;
-    }
-
-    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 {
-            TargetList => {
-                let mut targets = rustc_target::spec::TARGETS.to_vec();
-                targets.sort_unstable();
-                println!("{}", targets.join("\n"));
-            }
-            Sysroot => println!("{}", sess.sysroot.display()),
-            TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
-            TargetSpec => {
-                println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
-            }
-            FileNames | CrateName => {
-                let attrs = attrs.as_ref().unwrap();
-                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;
-                }
-                let crate_types = collect_crate_types(sess, attrs);
-                for &style in &crate_types {
-                    let fname =
-                        rustc_session::output::filename_for_input(sess, style, id, &t_outputs);
-                    println!("{}", fname.file_name().unwrap().to_string_lossy());
-                }
-            }
-            Cfg => {
-                let mut cfgs = sess
-                    .parse_sess
-                    .config
-                    .iter()
-                    .filter_map(|&(name, value)| {
-                        // Note that crt-static is a specially recognized cfg
-                        // directive that's printed out here as part of
-                        // rust-lang/rust#37406, but in general the
-                        // `target_feature` cfg is gated under
-                        // rust-lang/rust#29717. For now this is just
-                        // specifically allowing the crt-static cfg and that's
-                        // it, this is intended to get into Cargo and then go
-                        // through to build scripts.
-                        if (name != sym::target_feature || value != Some(sym::crt_dash_static))
-                            && !sess.is_nightly_build()
-                            && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
-                        {
-                            return None;
-                        }
-
-                        if let Some(value) = value {
-                            Some(format!("{name}=\"{value}\""))
-                        } else {
-                            Some(name.to_string())
-                        }
-                    })
-                    .collect::<Vec<String>>();
-
-                cfgs.sort();
-                for cfg in cfgs {
-                    println!("{cfg}");
-                }
-            }
-            CallingConventions => {
-                let mut calling_conventions = rustc_target::spec::abi::all_names();
-                calling_conventions.sort_unstable();
-                println!("{}", calling_conventions.join("\n"));
-            }
-            RelocationModels
-            | CodeModels
-            | TlsModels
-            | TargetCPUs
-            | StackProtectorStrategies
-            | TargetFeatures => {
-                codegen_backend.print(*req, sess);
-            }
-            // Any output here interferes with Cargo's parsing of other printed output
-            NativeStaticLibs => {}
-            LinkArgs => {}
-            SplitDebuginfo => {
-                use rustc_target::spec::SplitDebuginfo::{Off, Packed, Unpacked};
-
-                for split in &[Off, Packed, Unpacked] {
-                    let stable = sess.target.options.supported_split_debuginfo.contains(split);
-                    let unstable_ok = sess.unstable_options();
-                    if stable || unstable_ok {
-                        println!("{split}");
-                    }
-                }
-            }
-        }
-    }
-    Compilation::Stop
-}
-
-/// Prints version information
-///
-/// NOTE: this is a macro to support drivers built at a different time than the main `rustc_driver` crate.
-pub macro version($binary: literal, $matches: expr) {
-    fn unw(x: Option<&str>) -> &str {
-        x.unwrap_or("unknown")
-    }
-    $crate::version_at_macro_invocation(
-        $binary,
-        $matches,
-        unw(option_env!("CFG_VERSION")),
-        unw(option_env!("CFG_VER_HASH")),
-        unw(option_env!("CFG_VER_DATE")),
-        unw(option_env!("CFG_RELEASE")),
-    )
-}
-
-#[doc(hidden)] // use the macro instead
-pub fn version_at_macro_invocation(
-    binary: &str,
-    matches: &getopts::Matches,
-    version: &str,
-    commit_hash: &str,
-    commit_date: &str,
-    release: &str,
-) {
-    let verbose = matches.opt_present("verbose");
-
-    println!("{binary} {version}");
-
-    if verbose {
-        println!("binary: {binary}");
-        println!("commit-hash: {commit_hash}");
-        println!("commit-date: {commit_date}");
-        println!("host: {}", config::host_triple());
-        println!("release: {release}");
-
-        let debug_flags = matches.opt_strs("Z");
-        let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
-        get_codegen_backend(&None, backend_name).print_version();
-    }
-}
-
-fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
-    let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() };
-    let mut options = getopts::Options::new();
-    for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
-        (option.apply)(&mut options);
-    }
-    let message = "Usage: rustc [OPTIONS] INPUT";
-    let nightly_help = if nightly_build {
-        "\n    -Z help             Print unstable compiler options"
-    } else {
-        ""
-    };
-    let verbose_help = if verbose {
-        ""
-    } else {
-        "\n    --help -v           Print the full set of options rustc accepts"
-    };
-    let at_path = if verbose {
-        "    @path               Read newline separated options from `path`\n"
-    } else {
-        ""
-    };
-    println!(
-        "{options}{at_path}\nAdditional help:
-    -C help             Print codegen options
-    -W help             \
-              Print 'lint' options and default settings{nightly}{verbose}\n",
-        options = options.usage(message),
-        at_path = at_path,
-        nightly = nightly_help,
-        verbose = verbose_help
-    );
-}
-
-fn print_wall_help() {
-    println!(
-        "
-The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by
-default. Use `rustc -W help` to see all available lints. It's more common to put
-warning settings in the crate root using `#![warn(LINT_NAME)]` instead of using
-the command line flag directly.
-"
-    );
-}
-
-/// Write to stdout lint command options, together with a list of all available lints
-pub fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) {
-    println!(
-        "
-Available lint options:
-    -W <foo>           Warn about <foo>
-    -A <foo>           \
-              Allow <foo>
-    -D <foo>           Deny <foo>
-    -F <foo>           Forbid <foo> \
-              (deny <foo> and all attempts to override)
-
-"
-    );
-
-    fn sort_lints(sess: &Session, mut lints: Vec<&'static Lint>) -> Vec<&'static Lint> {
-        // The sort doesn't case-fold but it's doubtful we care.
-        lints.sort_by_cached_key(|x: &&Lint| (x.default_level(sess.edition()), x.name));
-        lints
-    }
-
-    fn sort_lint_groups(
-        lints: Vec<(&'static str, Vec<LintId>, bool)>,
-    ) -> Vec<(&'static str, Vec<LintId>)> {
-        let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
-        lints.sort_by_key(|l| l.0);
-        lints
-    }
-
-    let (plugin, builtin): (Vec<_>, _) =
-        lint_store.get_lints().iter().cloned().partition(|&lint| lint.is_plugin);
-    let plugin = sort_lints(sess, plugin);
-    let builtin = sort_lints(sess, builtin);
-
-    let (plugin_groups, builtin_groups): (Vec<_>, _) =
-        lint_store.get_lint_groups().partition(|&(.., p)| p);
-    let plugin_groups = sort_lint_groups(plugin_groups);
-    let builtin_groups = sort_lint_groups(builtin_groups);
-
-    let max_name_len =
-        plugin.iter().chain(&builtin).map(|&s| s.name.chars().count()).max().unwrap_or(0);
-    let padded = |x: &str| {
-        let mut s = " ".repeat(max_name_len - x.chars().count());
-        s.push_str(x);
-        s
-    };
-
-    println!("Lint checks provided by rustc:\n");
-
-    let print_lints = |lints: Vec<&Lint>| {
-        println!("    {}  {:7.7}  {}", padded("name"), "default", "meaning");
-        println!("    {}  {:7.7}  {}", padded("----"), "-------", "-------");
-        for lint in lints {
-            let name = lint.name_lower().replace('_', "-");
-            println!(
-                "    {}  {:7.7}  {}",
-                padded(&name),
-                lint.default_level(sess.edition()).as_str(),
-                lint.desc
-            );
-        }
-        println!("\n");
-    };
-
-    print_lints(builtin);
-
-    let max_name_len = max(
-        "warnings".len(),
-        plugin_groups
-            .iter()
-            .chain(&builtin_groups)
-            .map(|&(s, _)| s.chars().count())
-            .max()
-            .unwrap_or(0),
-    );
-
-    let padded = |x: &str| {
-        let mut s = " ".repeat(max_name_len - x.chars().count());
-        s.push_str(x);
-        s
-    };
-
-    println!("Lint groups provided by rustc:\n");
-
-    let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>, all_warnings| {
-        println!("    {}  sub-lints", padded("name"));
-        println!("    {}  ---------", padded("----"));
-
-        if all_warnings {
-            println!("    {}  all lints that are set to issue warnings", padded("warnings"));
-        }
-
-        for (name, to) in lints {
-            let name = name.to_lowercase().replace('_', "-");
-            let desc = to
-                .into_iter()
-                .map(|x| x.to_string().replace('_', "-"))
-                .collect::<Vec<String>>()
-                .join(", ");
-            println!("    {}  {}", padded(&name), desc);
-        }
-        println!("\n");
-    };
-
-    print_lint_groups(builtin_groups, true);
-
-    match (loaded_plugins, plugin.len(), plugin_groups.len()) {
-        (false, 0, _) | (false, _, 0) => {
-            println!("Lint tools like Clippy can provide additional lints and lint groups.");
-        }
-        (false, ..) => panic!("didn't load lint plugins but got them anyway!"),
-        (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
-        (true, l, g) => {
-            if l > 0 {
-                println!("Lint checks provided by plugins loaded by this crate:\n");
-                print_lints(plugin);
-            }
-            if g > 0 {
-                println!("Lint groups provided by plugins loaded by this crate:\n");
-                print_lint_groups(plugin_groups, false);
-            }
-        }
-    }
-}
-
-fn describe_debug_flags() {
-    println!("\nAvailable options:\n");
-    print_flag_list("-Z", config::Z_OPTIONS);
-}
-
-fn describe_codegen_flags() {
-    println!("\nAvailable codegen options:\n");
-    print_flag_list("-C", config::CG_OPTIONS);
-}
-
-pub fn print_flag_list<T>(
-    cmdline_opt: &str,
-    flag_list: &[(&'static str, T, &'static str, &'static str)],
-) {
-    let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0);
-
-    for &(name, _, _, desc) in flag_list {
-        println!(
-            "    {} {:>width$}=val -- {}",
-            cmdline_opt,
-            name.replace('_', "-"),
-            desc,
-            width = max_len
-        );
-    }
-}
-
-/// Process command line options. Emits messages as appropriate. If compilation
-/// should continue, returns a getopts::Matches object parsed from args,
-/// otherwise returns `None`.
-///
-/// The compiler's handling of options is a little complicated as it ties into
-/// our stability story. The current intention of each compiler option is to
-/// have one of two modes:
-///
-/// 1. An option is stable and can be used everywhere.
-/// 2. An option is unstable, and can only be used on nightly.
-///
-/// Like unstable library and language features, however, unstable options have
-/// always required a form of "opt in" to indicate that you're using them. This
-/// provides the easy ability to scan a code base to check to see if anything
-/// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
-///
-/// All options behind `-Z` are considered unstable by default. Other top-level
-/// options can also be considered unstable, and they were unlocked through the
-/// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
-/// instability in both cases, though.
-///
-/// So with all that in mind, the comments below have some more detail about the
-/// contortions done here to get things to work out correctly.
-pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
-    // Throw away the first argument, the name of the binary
-    let args = &args[1..];
-
-    if args.is_empty() {
-        // user did not write `-v` nor `-Z unstable-options`, so do not
-        // include that extra information.
-        let nightly_build =
-            rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build();
-        usage(false, false, nightly_build);
-        return None;
-    }
-
-    // Parse with *all* options defined in the compiler, we don't worry about
-    // option stability here we just want to parse as much as possible.
-    let mut options = getopts::Options::new();
-    for option in config::rustc_optgroups() {
-        (option.apply)(&mut options);
-    }
-    let matches = options.parse(args).unwrap_or_else(|e| {
-        let msg = match e {
-            getopts::Fail::UnrecognizedOption(ref opt) => CG_OPTIONS
-                .iter()
-                .map(|&(name, ..)| ('C', name))
-                .chain(Z_OPTIONS.iter().map(|&(name, ..)| ('Z', name)))
-                .find(|&(_, name)| *opt == name.replace('_', "-"))
-                .map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")),
-            _ => None,
-        };
-        early_error(ErrorOutputType::default(), &msg.unwrap_or_else(|| e.to_string()));
-    });
-
-    // For all options we just parsed, we check a few aspects:
-    //
-    // * If the option is stable, we're all good
-    // * If the option wasn't passed, we're all good
-    // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
-    //   ourselves), then we require the `-Z unstable-options` flag to unlock
-    //   this option that was passed.
-    // * If we're a nightly compiler, then unstable options are now unlocked, so
-    //   we're good to go.
-    // * Otherwise, if we're an unstable option then we generate an error
-    //   (unstable option being used on stable)
-    nightly_options::check_nightly_options(&matches, &config::rustc_optgroups());
-
-    if matches.opt_present("h") || matches.opt_present("help") {
-        // Only show unstable options in --help if we accept unstable options.
-        let unstable_enabled = nightly_options::is_unstable_enabled(&matches);
-        let nightly_build = nightly_options::match_is_nightly_build(&matches);
-        usage(matches.opt_present("verbose"), unstable_enabled, nightly_build);
-        return None;
-    }
-
-    // Handle the special case of -Wall.
-    let wall = matches.opt_strs("W");
-    if wall.iter().any(|x| *x == "all") {
-        print_wall_help();
-        rustc_errors::FatalError.raise();
-    }
-
-    // Don't handle -W help here, because we might first load plugins.
-    let debug_flags = matches.opt_strs("Z");
-    if debug_flags.iter().any(|x| *x == "help") {
-        describe_debug_flags();
-        return None;
-    }
-
-    let cg_flags = matches.opt_strs("C");
-
-    if cg_flags.iter().any(|x| *x == "help") {
-        describe_codegen_flags();
-        return None;
-    }
-
-    if cg_flags.iter().any(|x| *x == "no-stack-check") {
-        early_warn(
-            ErrorOutputType::default(),
-            "the --no-stack-check flag is deprecated and does nothing",
-        );
-    }
-
-    if cg_flags.iter().any(|x| *x == "passes=list") {
-        let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
-        get_codegen_backend(&None, backend_name).print_passes();
-        return None;
-    }
-
-    if matches.opt_present("version") {
-        version!("rustc", &matches);
-        return None;
-    }
-
-    Some(matches)
-}
-
-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(),
-            input.clone(),
-            &sess.parse_sess,
-        ),
-    }
-}
-
-/// Gets a list of extra command-line flags provided by the user, as strings.
-///
-/// This function is used during ICEs to show more information useful for
-/// debugging, since some ICEs only happens with non-default compiler flags
-/// (and the users don't always report them).
-fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
-    let mut args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).peekable();
-
-    let mut result = Vec::new();
-    let mut excluded_cargo_defaults = false;
-    while let Some(arg) = args.next() {
-        if let Some(a) = ICE_REPORT_COMPILER_FLAGS.iter().find(|a| arg.starts_with(*a)) {
-            let content = if arg.len() == a.len() {
-                // A space-separated option, like `-C incremental=foo` or `--crate-type rlib`
-                match args.next() {
-                    Some(arg) => arg.to_string(),
-                    None => continue,
-                }
-            } else if arg.get(a.len()..a.len() + 1) == Some("=") {
-                // An equals option, like `--crate-type=rlib`
-                arg[a.len() + 1..].to_string()
-            } else {
-                // A non-space option, like `-Cincremental=foo`
-                arg[a.len()..].to_string()
-            };
-            let option = content.split_once('=').map(|s| s.0).unwrap_or(&content);
-            if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| option == *exc) {
-                excluded_cargo_defaults = true;
-            } else {
-                result.push(a.to_string());
-                match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| option == **s) {
-                    Some(s) => result.push(format!("{s}=[REDACTED]")),
-                    None => result.push(content),
-                }
-            }
-        }
-    }
-
-    if !result.is_empty() { Some((result, excluded_cargo_defaults)) } else { None }
-}
-
-/// Runs a closure and catches unwinds triggered by fatal errors.
-///
-/// The compiler currently unwinds with a special sentinel value to abort
-/// compilation on fatal errors. This function catches that sentinel and turns
-/// the panic into a `Result` instead.
-pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorGuaranteed> {
-    catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
-        if value.is::<rustc_errors::FatalErrorMarker>() {
-            ErrorGuaranteed::unchecked_claim_error_was_emitted()
-        } else {
-            panic::resume_unwind(value);
-        }
-    })
-}
-
-/// Variant of `catch_fatal_errors` for the `interface::Result` return type
-/// that also computes the exit code.
-pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
-    let result = catch_fatal_errors(f).and_then(|result| result);
-    match result {
-        Ok(()) => EXIT_SUCCESS,
-        Err(_) => EXIT_FAILURE,
-    }
-}
-
-static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
-    LazyLock::new(|| {
-        let hook = panic::take_hook();
-        panic::set_hook(Box::new(|info| {
-            // If the error was caused by a broken pipe then this is not a bug.
-            // Write the error and return immediately. See #98700.
-            #[cfg(windows)]
-            if let Some(msg) = info.payload().downcast_ref::<String>() {
-                if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)")
-                {
-                    early_error_no_abort(ErrorOutputType::default(), &msg);
-                    return;
-                }
-            };
-
-            // Invoke the default handler, which prints the actual panic message and optionally a backtrace
-            // Don't do this for delayed bugs, which already emit their own more useful backtrace.
-            if !info.payload().is::<rustc_errors::DelayedBugPanic>() {
-                (*DEFAULT_HOOK)(info);
-
-                // Separate the output with an empty line
-                eprintln!();
-            }
-
-            // Print the ICE message
-            report_ice(info, BUG_REPORT_URL);
-        }));
-        hook
-    });
-
-/// Prints the ICE message, including query stack, but without backtrace.
-///
-/// The message will point the user at `bug_report_url` to report the ICE.
-///
-/// When `install_ice_hook` is called, this function will be called as the panic
-/// hook.
-pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
-    let fallback_bundle =
-        rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
-    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
-        rustc_errors::ColorConfig::Auto,
-        None,
-        None,
-        fallback_bundle,
-        false,
-        false,
-        None,
-        false,
-        false,
-    ));
-    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
-
-    // a .span_bug or .bug call has already printed what
-    // it wants to print.
-    if !info.payload().is::<rustc_errors::ExplicitBug>()
-        && !info.payload().is::<rustc_errors::DelayedBugPanic>()
-    {
-        let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
-        handler.emit_diagnostic(&mut d);
-    }
-
-    handler.emit_note(session_diagnostics::Ice);
-    handler.emit_note(session_diagnostics::IceBugReport { bug_report_url });
-    handler.emit_note(session_diagnostics::IceVersion {
-        version: util::version_str!().unwrap_or("unknown_version"),
-        triple: config::host_triple(),
-    });
-
-    if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
-        handler.emit_note(session_diagnostics::IceFlags { flags: flags.join(" ") });
-        if excluded_cargo_defaults {
-            handler.emit_note(session_diagnostics::IceExcludeCargoDefaults);
-        }
-    }
-
-    // If backtraces are enabled, also print the query stack
-    let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");
-
-    let num_frames = if backtrace { None } else { Some(2) };
-
-    interface::try_print_query_stack(&handler, num_frames);
-
-    #[cfg(windows)]
-    unsafe {
-        if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
-            // Trigger a debugger if we crashed during bootstrap
-            winapi::um::debugapi::DebugBreak();
-        }
-    }
-}
-
-/// Installs a panic hook that will print the ICE message on unexpected panics.
-///
-/// A custom rustc driver can skip calling this to set up a custom ICE hook.
-pub fn install_ice_hook() {
-    // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
-    // full backtraces. When a compiler ICE happens, we want to gather
-    // as much information as possible to present in the issue opened
-    // by the user. Compiler developers and other rustc users can
-    // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
-    // (e.g. `RUST_BACKTRACE=1`)
-    if std::env::var("RUST_BACKTRACE").is_err() {
-        std::env::set_var("RUST_BACKTRACE", "full");
-    }
-    LazyLock::force(&DEFAULT_HOOK);
-}
-
-/// This allows tools to enable rust logging without having to magically match rustc's
-/// tracing crate version.
-pub fn init_rustc_env_logger() {
-    init_rustc_env_logger_with_backtrace_option(&None);
-}
-
-/// This allows tools to enable rust logging without having to magically match rustc's
-/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to
-/// choose a target module you wish to show backtraces along with its logging.
-pub fn init_rustc_env_logger_with_backtrace_option(backtrace_target: &Option<String>) {
-    if let Err(error) = rustc_log::init_rustc_env_logger_with_backtrace_option(backtrace_target) {
-        early_error(ErrorOutputType::default(), &error.to_string());
-    }
-}
-
-/// This allows tools to enable rust logging without having to magically match rustc's
-/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
-/// other than `RUSTC_LOG`.
-pub fn init_env_logger(env: &str) {
-    if let Err(error) = rustc_log::init_env_logger(env) {
-        early_error(ErrorOutputType::default(), &error.to_string());
-    }
-}
-
-#[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))]
-mod signal_handler {
-    extern "C" {
-        fn backtrace_symbols_fd(
-            buffer: *const *mut libc::c_void,
-            size: libc::c_int,
-            fd: libc::c_int,
-        );
-    }
-
-    extern "C" fn print_stack_trace(_: libc::c_int) {
-        const MAX_FRAMES: usize = 256;
-        static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] =
-            [std::ptr::null_mut(); MAX_FRAMES];
-        unsafe {
-            let depth = libc::backtrace(STACK_TRACE.as_mut_ptr(), MAX_FRAMES as i32);
-            if depth == 0 {
-                return;
-            }
-            backtrace_symbols_fd(STACK_TRACE.as_ptr(), depth, 2);
-        }
-    }
-
-    /// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
-    /// process, print a stack trace and then exit.
-    pub(super) fn install() {
-        unsafe {
-            const ALT_STACK_SIZE: usize = libc::MINSIGSTKSZ + 64 * 1024;
-            let mut alt_stack: libc::stack_t = std::mem::zeroed();
-            alt_stack.ss_sp =
-                std::alloc::alloc(std::alloc::Layout::from_size_align(ALT_STACK_SIZE, 1).unwrap())
-                    as *mut libc::c_void;
-            alt_stack.ss_size = ALT_STACK_SIZE;
-            libc::sigaltstack(&alt_stack, std::ptr::null_mut());
-
-            let mut sa: libc::sigaction = std::mem::zeroed();
-            sa.sa_sigaction = print_stack_trace as libc::sighandler_t;
-            sa.sa_flags = libc::SA_NODEFER | libc::SA_RESETHAND | libc::SA_ONSTACK;
-            libc::sigemptyset(&mut sa.sa_mask);
-            libc::sigaction(libc::SIGSEGV, &sa, std::ptr::null_mut());
-        }
-    }
-}
-
-#[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))]
-mod signal_handler {
-    pub(super) fn install() {}
-}
-
-pub fn main() -> ! {
-    let start_time = Instant::now();
-    let start_rss = get_resident_set_size();
-    signal_handler::install();
-    let mut callbacks = TimePassesCallbacks::default();
-    install_ice_hook();
-    let exit_code = catch_with_exit_code(|| {
-        let args = env::args_os()
-            .enumerate()
-            .map(|(i, arg)| {
-                arg.into_string().unwrap_or_else(|arg| {
-                    early_error(
-                        ErrorOutputType::default(),
-                        &format!("argument {i} is not valid Unicode: {arg:?}"),
-                    )
-                })
-            })
-            .collect::<Vec<_>>();
-        RunCompiler::new(&args, &mut callbacks).run()
-    });
-
-    if callbacks.time_passes {
-        let end_rss = get_resident_set_size();
-        print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss);
-    }
-
-    process::exit(exit_code)
-}
+pub use rustc_driver_impl::*;
diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs
deleted file mode 100644 (file)
index 446c683..0000000
+++ /dev/null
@@ -1,522 +0,0 @@
-//! The various pretty-printing routines.
-
-use crate::session_diagnostics::UnprettyDumpFail;
-use rustc_ast as ast;
-use rustc_ast_pretty::pprust;
-use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
-use rustc_hir_pretty as pprust_hir;
-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::{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;
-
-pub use self::PpMode::*;
-pub use self::PpSourceMode::*;
-use crate::abort_on_err;
-
-// This slightly awkward construction is to allow for each PpMode to
-// choose whether it needs to do analyses (which can consume the
-// Session) and then pass through the session (now attached to the
-// analysis results) on to the chosen pretty-printer, along with the
-// `&PpAnn` object.
-//
-// Note that since the `&PrinterSupport` is freshly constructed on each
-// call, it would not make sense to try to attach the lifetime of `self`
-// to the lifetime of the `&PrinterObject`.
-
-/// Constructs a `PrinterSupport` object and passes it to `f`.
-fn call_with_pp_support<'tcx, A, F>(
-    ppmode: &PpSourceMode,
-    sess: &'tcx Session,
-    tcx: Option<TyCtxt<'tcx>>,
-    f: F,
-) -> A
-where
-    F: FnOnce(&dyn PrinterSupport) -> A,
-{
-    match *ppmode {
-        Normal | Expanded => {
-            let annotation = NoAnn { sess, tcx };
-            f(&annotation)
-        }
-
-        Identified | ExpandedIdentified => {
-            let annotation = IdentifiedAnnotation { sess, tcx };
-            f(&annotation)
-        }
-        ExpandedHygiene => {
-            let annotation = HygieneAnnotation { sess };
-            f(&annotation)
-        }
-    }
-}
-fn call_with_pp_support_hir<A, F>(ppmode: &PpHirMode, tcx: TyCtxt<'_>, f: F) -> A
-where
-    F: FnOnce(&dyn HirPrinterSupport<'_>, hir_map::Map<'_>) -> A,
-{
-    match *ppmode {
-        PpHirMode::Normal => {
-            let annotation = NoAnn { sess: tcx.sess, tcx: Some(tcx) };
-            f(&annotation, tcx.hir())
-        }
-
-        PpHirMode::Identified => {
-            let annotation = IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) };
-            f(&annotation, tcx.hir())
-        }
-        PpHirMode::Typed => {
-            abort_on_err(tcx.analysis(()), tcx.sess);
-
-            let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) };
-            tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir()))
-        }
-    }
-}
-
-trait PrinterSupport: pprust::PpAnn {
-    /// Provides a uniform interface for re-extracting a reference to a
-    /// `Session` from a value that now owns it.
-    fn sess(&self) -> &Session;
-
-    /// Produces the pretty-print annotation object.
-    ///
-    /// (Rust does not yet support upcasting from a trait object to
-    /// an object for one of its supertraits.)
-    fn pp_ann(&self) -> &dyn pprust::PpAnn;
-}
-
-trait HirPrinterSupport<'hir>: pprust_hir::PpAnn {
-    /// Provides a uniform interface for re-extracting a reference to a
-    /// `Session` from a value that now owns it.
-    fn sess(&self) -> &Session;
-
-    /// Provides a uniform interface for re-extracting a reference to an
-    /// `hir_map::Map` from a value that now owns it.
-    fn hir_map(&self) -> Option<hir_map::Map<'hir>>;
-
-    /// Produces the pretty-print annotation object.
-    ///
-    /// (Rust does not yet support upcasting from a trait object to
-    /// an object for one of its supertraits.)
-    fn pp_ann(&self) -> &dyn pprust_hir::PpAnn;
-}
-
-struct NoAnn<'hir> {
-    sess: &'hir Session,
-    tcx: Option<TyCtxt<'hir>>,
-}
-
-impl<'hir> PrinterSupport for NoAnn<'hir> {
-    fn sess(&self) -> &Session {
-        self.sess
-    }
-
-    fn pp_ann(&self) -> &dyn pprust::PpAnn {
-        self
-    }
-}
-
-impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> {
-    fn sess(&self) -> &Session {
-        self.sess
-    }
-
-    fn hir_map(&self) -> Option<hir_map::Map<'hir>> {
-        self.tcx.map(|tcx| tcx.hir())
-    }
-
-    fn pp_ann(&self) -> &dyn pprust_hir::PpAnn {
-        self
-    }
-}
-
-impl<'hir> pprust::PpAnn for NoAnn<'hir> {}
-impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> {
-    fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
-        if let Some(tcx) = self.tcx {
-            pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested)
-        }
-    }
-}
-
-struct IdentifiedAnnotation<'hir> {
-    sess: &'hir Session,
-    tcx: Option<TyCtxt<'hir>>,
-}
-
-impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> {
-    fn sess(&self) -> &Session {
-        self.sess
-    }
-
-    fn pp_ann(&self) -> &dyn pprust::PpAnn {
-        self
-    }
-}
-
-impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> {
-    fn pre(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
-        if let pprust::AnnNode::Expr(_) = node {
-            s.popen();
-        }
-    }
-    fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
-        match node {
-            pprust::AnnNode::Crate(_) | pprust::AnnNode::Ident(_) | pprust::AnnNode::Name(_) => {}
-
-            pprust::AnnNode::Item(item) => {
-                s.s.space();
-                s.synth_comment(item.id.to_string())
-            }
-            pprust::AnnNode::SubItem(id) => {
-                s.s.space();
-                s.synth_comment(id.to_string())
-            }
-            pprust::AnnNode::Block(blk) => {
-                s.s.space();
-                s.synth_comment(format!("block {}", blk.id))
-            }
-            pprust::AnnNode::Expr(expr) => {
-                s.s.space();
-                s.synth_comment(expr.id.to_string());
-                s.pclose()
-            }
-            pprust::AnnNode::Pat(pat) => {
-                s.s.space();
-                s.synth_comment(format!("pat {}", pat.id));
-            }
-        }
-    }
-}
-
-impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> {
-    fn sess(&self) -> &Session {
-        self.sess
-    }
-
-    fn hir_map(&self) -> Option<hir_map::Map<'hir>> {
-        self.tcx.map(|tcx| tcx.hir())
-    }
-
-    fn pp_ann(&self) -> &dyn pprust_hir::PpAnn {
-        self
-    }
-}
-
-impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
-    fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
-        if let Some(ref tcx) = self.tcx {
-            pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested)
-        }
-    }
-    fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
-        if let pprust_hir::AnnNode::Expr(_) = node {
-            s.popen();
-        }
-    }
-    fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
-        match node {
-            pprust_hir::AnnNode::Name(_) => {}
-            pprust_hir::AnnNode::Item(item) => {
-                s.s.space();
-                s.synth_comment(format!("hir_id: {}", item.hir_id()));
-            }
-            pprust_hir::AnnNode::SubItem(id) => {
-                s.s.space();
-                s.synth_comment(id.to_string());
-            }
-            pprust_hir::AnnNode::Block(blk) => {
-                s.s.space();
-                s.synth_comment(format!("block hir_id: {}", blk.hir_id));
-            }
-            pprust_hir::AnnNode::Expr(expr) => {
-                s.s.space();
-                s.synth_comment(format!("expr hir_id: {}", expr.hir_id));
-                s.pclose();
-            }
-            pprust_hir::AnnNode::Pat(pat) => {
-                s.s.space();
-                s.synth_comment(format!("pat hir_id: {}", pat.hir_id));
-            }
-            pprust_hir::AnnNode::Arm(arm) => {
-                s.s.space();
-                s.synth_comment(format!("arm hir_id: {}", arm.hir_id));
-            }
-        }
-    }
-}
-
-struct HygieneAnnotation<'a> {
-    sess: &'a Session,
-}
-
-impl<'a> PrinterSupport for HygieneAnnotation<'a> {
-    fn sess(&self) -> &Session {
-        self.sess
-    }
-
-    fn pp_ann(&self) -> &dyn pprust::PpAnn {
-        self
-    }
-}
-
-impl<'a> pprust::PpAnn for HygieneAnnotation<'a> {
-    fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
-        match node {
-            pprust::AnnNode::Ident(&Ident { name, span }) => {
-                s.s.space();
-                s.synth_comment(format!("{}{:?}", name.as_u32(), span.ctxt()))
-            }
-            pprust::AnnNode::Name(&name) => {
-                s.s.space();
-                s.synth_comment(name.as_u32().to_string())
-            }
-            pprust::AnnNode::Crate(_) => {
-                s.s.hardbreak();
-                let verbose = self.sess.verbose();
-                s.synth_comment(rustc_span::hygiene::debug_hygiene_data(verbose));
-                s.s.hardbreak_if_not_bol();
-            }
-            _ => {}
-        }
-    }
-}
-
-struct TypedAnnotation<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    maybe_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
-}
-
-impl<'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'tcx> {
-    fn sess(&self) -> &Session {
-        self.tcx.sess
-    }
-
-    fn hir_map(&self) -> Option<hir_map::Map<'tcx>> {
-        Some(self.tcx.hir())
-    }
-
-    fn pp_ann(&self) -> &dyn pprust_hir::PpAnn {
-        self
-    }
-}
-
-impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> {
-    fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
-        let old_maybe_typeck_results = self.maybe_typeck_results.get();
-        if let pprust_hir::Nested::Body(id) = nested {
-            self.maybe_typeck_results.set(Some(self.tcx.typeck_body(id)));
-        }
-        let pp_ann = &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>);
-        pprust_hir::PpAnn::nested(pp_ann, state, nested);
-        self.maybe_typeck_results.set(old_maybe_typeck_results);
-    }
-    fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
-        if let pprust_hir::AnnNode::Expr(_) = node {
-            s.popen();
-        }
-    }
-    fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
-        if let pprust_hir::AnnNode::Expr(expr) = node {
-            let typeck_results = self.maybe_typeck_results.get().or_else(|| {
-                self.tcx
-                    .hir()
-                    .maybe_body_owned_by(expr.hir_id.owner.def_id)
-                    .map(|body_id| self.tcx.typeck_body(body_id))
-            });
-
-            if let Some(typeck_results) = typeck_results {
-                s.s.space();
-                s.s.word("as");
-                s.s.space();
-                s.s.word(typeck_results.expr_ty(expr).to_string());
-            }
-
-            s.pclose();
-        }
-    }
-}
-
-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)
-            .expect("get_source_file")
-            .src
-            .as_ref()
-            .expect("src"),
-    );
-    (src, src_name)
-}
-
-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) {
-                sess.emit_fatal(UnprettyDumpFail {
-                    path: p.display().to_string(),
-                    err: e.to_string(),
-                });
-            }
-        }
-    }
-}
-
-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) => {
-            // Silently ignores an identified node.
-            call_with_pp_support(&s, sess, None, move |annotation| {
-                debug!("pretty printing source code {:?}", s);
-                let sess = annotation.sess();
-                let parse = &sess.parse_sess;
-                pprust::print_crate(
-                    sess.source_map(),
-                    krate,
-                    src_name,
-                    src,
-                    annotation.pp_ann(),
-                    false,
-                    parse.edition,
-                    &sess.parse_sess.attr_id_generator,
-                )
-            })
-        }
-        AstTree(PpAstTreeMode::Normal) => {
-            debug!("pretty printing AST tree");
-            format!("{krate:#?}")
-        }
-        _ => unreachable!(),
-    };
-
-    write_or_print(&out, sess);
-}
-
-pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) {
-    if ppm.needs_analysis() {
-        abort_on_err(print_with_analysis(tcx, ppm), tcx.sess);
-        return;
-    }
-
-    let (src, src_name) = get_source(tcx.sess);
-
-    let out = match ppm {
-        Source(s) => {
-            // Silently ignores an identified node.
-            call_with_pp_support(&s, tcx.sess, Some(tcx), move |annotation| {
-                debug!("pretty printing source code {:?}", s);
-                let sess = annotation.sess();
-                let parse = &sess.parse_sess;
-                pprust::print_crate(
-                    sess.source_map(),
-                    &tcx.resolver_for_lowering(()).borrow().1,
-                    src_name,
-                    src,
-                    annotation.pp_ann(),
-                    true,
-                    parse.edition,
-                    &sess.parse_sess.attr_id_generator,
-                )
-            })
-        }
-
-        AstTree(PpAstTreeMode::Expanded) => {
-            debug!("pretty-printing expanded AST");
-            format!("{:#?}", tcx.resolver_for_lowering(()).borrow().1)
-        }
-
-        Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| {
-            debug!("pretty printing HIR {:?}", s);
-            let sess = annotation.sess();
-            let sm = sess.source_map();
-            let attrs = |id| hir_map.attrs(id);
-            pprust_hir::print_crate(
-                sm,
-                hir_map.root_module(),
-                src_name,
-                src,
-                &attrs,
-                annotation.pp_ann(),
-            )
-        }),
-
-        HirTree => {
-            call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, hir_map| {
-                debug!("pretty printing HIR tree");
-                format!("{:#?}", hir_map.krate())
-            })
-        }
-
-        _ => unreachable!(),
-    };
-
-    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) -> Result<(), ErrorGuaranteed> {
-    tcx.analysis(())?;
-    let out = match ppm {
-        Mir => {
-            let mut out = Vec::new();
-            write_mir_pretty(tcx, None, &mut out).unwrap();
-            String::from_utf8(out).unwrap()
-        }
-
-        MirCFG => {
-            let mut out = Vec::new();
-            write_mir_graphviz(tcx, None, &mut out).unwrap();
-            String::from_utf8(out).unwrap()
-        }
-
-        ThirTree => {
-            let mut out = String::new();
-            abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
-            debug!("pretty printing THIR tree");
-            for did in tcx.hir().body_owners() {
-                let _ = writeln!(
-                    out,
-                    "{:?}:\n{}\n",
-                    did,
-                    tcx.thir_tree(ty::WithOptConstParam::unknown(did))
-                );
-            }
-            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, tcx.sess);
-
-    Ok(())
-}
diff --git a/compiler/rustc_driver/src/session_diagnostics.rs b/compiler/rustc_driver/src/session_diagnostics.rs
deleted file mode 100644 (file)
index a7aef9c..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-use rustc_macros::Diagnostic;
-
-#[derive(Diagnostic)]
-#[diag(driver_rlink_unable_to_read)]
-pub(crate) struct RlinkUnableToRead {
-    pub err: std::io::Error,
-}
-
-#[derive(Diagnostic)]
-#[diag(driver_rlink_wrong_file_type)]
-pub(crate) struct RLinkWrongFileType;
-
-#[derive(Diagnostic)]
-#[diag(driver_rlink_empty_version_number)]
-pub(crate) struct RLinkEmptyVersionNumber;
-
-#[derive(Diagnostic)]
-#[diag(driver_rlink_encoding_version_mismatch)]
-pub(crate) struct RLinkEncodingVersionMismatch {
-    pub version_array: String,
-    pub rlink_version: u32,
-}
-
-#[derive(Diagnostic)]
-#[diag(driver_rlink_rustc_version_mismatch)]
-pub(crate) struct RLinkRustcVersionMismatch<'a> {
-    pub rustc_version: String,
-    pub current_version: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(driver_rlink_no_a_file)]
-pub(crate) struct RlinkNotAFile;
-
-#[derive(Diagnostic)]
-#[diag(driver_unpretty_dump_fail)]
-pub(crate) struct UnprettyDumpFail {
-    pub path: String,
-    pub err: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(driver_ice)]
-pub(crate) struct Ice;
-
-#[derive(Diagnostic)]
-#[diag(driver_ice_bug_report)]
-pub(crate) struct IceBugReport<'a> {
-    pub bug_report_url: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(driver_ice_version)]
-pub(crate) struct IceVersion<'a> {
-    pub version: &'a str,
-    pub triple: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(driver_ice_flags)]
-pub(crate) struct IceFlags {
-    pub flags: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(driver_ice_exclude_cargo_defaults)]
-pub(crate) struct IceExcludeCargoDefaults;
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
new file mode 100644 (file)
index 0000000..af85b12
--- /dev/null
@@ -0,0 +1,44 @@
+[package]
+name = "rustc_driver_impl"
+version = "0.0.0"
+edition = "2021"
+
+[lib]
+
+[dependencies]
+tracing = { version = "0.1.35" }
+serde_json = "1.0.59"
+rustc_log = { path = "../rustc_log" }
+rustc_middle = { path = "../rustc_middle" }
+rustc_ast_pretty = { path = "../rustc_ast_pretty" }
+rustc_target = { path = "../rustc_target" }
+rustc_lint = { path = "../rustc_lint" }
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_errors = { path = "../rustc_errors" }
+rustc_feature = { path = "../rustc_feature" }
+rustc_hir = { path = "../rustc_hir" }
+rustc_hir_pretty = { path = "../rustc_hir_pretty" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_metadata = { path = "../rustc_metadata" }
+rustc_parse = { path = "../rustc_parse" }
+rustc_plugin_impl = { path = "../rustc_plugin_impl" }
+rustc_save_analysis = { path = "../rustc_save_analysis" }
+rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
+rustc_session = { path = "../rustc_session" }
+rustc_error_codes = { path = "../rustc_error_codes" }
+rustc_interface = { path = "../rustc_interface" }
+rustc_ast = { path = "../rustc_ast" }
+rustc_span = { path = "../rustc_span" }
+rustc_hir_analysis = { path = "../rustc_hir_analysis" }
+
+[target.'cfg(unix)'.dependencies]
+libc = "0.2"
+
+[target.'cfg(windows)'.dependencies]
+winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] }
+
+[features]
+llvm = ['rustc_interface/llvm']
+max_level_info = ['rustc_log/max_level_info']
+rustc_use_parallel_compiler = ['rustc_data_structures/rustc_use_parallel_compiler', 'rustc_interface/rustc_use_parallel_compiler',
+    'rustc_middle/rustc_use_parallel_compiler']
diff --git a/compiler/rustc_driver_impl/README.md b/compiler/rustc_driver_impl/README.md
new file mode 100644 (file)
index 0000000..6d7fba3
--- /dev/null
@@ -0,0 +1,10 @@
+The `driver` crate is effectively the "main" function for the rust
+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
+options).
+
+For more information about how the driver works, see the [rustc dev guide].
+
+[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/rustc-driver.html
diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs
new file mode 100644 (file)
index 0000000..42c97cc
--- /dev/null
@@ -0,0 +1,51 @@
+use std::error;
+use std::fmt;
+use std::fs;
+use std::io;
+
+fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
+    if let Some(path) = arg.strip_prefix('@') {
+        let file = match fs::read_to_string(path) {
+            Ok(file) => file,
+            Err(ref err) if err.kind() == io::ErrorKind::InvalidData => {
+                return Err(Error::Utf8Error(Some(path.to_string())));
+            }
+            Err(err) => return Err(Error::IOError(path.to_string(), err)),
+        };
+        Ok(file.lines().map(ToString::to_string).collect())
+    } else {
+        Ok(vec![arg])
+    }
+}
+
+pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
+    let mut args = Vec::new();
+    for arg in at_args {
+        match arg_expand(arg.clone()) {
+            Ok(arg) => args.extend(arg),
+            Err(err) => rustc_session::early_error(
+                rustc_session::config::ErrorOutputType::default(),
+                &format!("Failed to load argument file: {err}"),
+            ),
+        }
+    }
+    args
+}
+
+#[derive(Debug)]
+pub enum Error {
+    Utf8Error(Option<String>),
+    IOError(String, io::Error),
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Error::Utf8Error(None) => write!(fmt, "Utf8 error"),
+            Error::Utf8Error(Some(path)) => write!(fmt, "Utf8 error in {path}"),
+            Error::IOError(path, err) => write!(fmt, "IO Error: {path}: {err}"),
+        }
+    }
+}
+
+impl error::Error for Error {}
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
new file mode 100644 (file)
index 0000000..1da13af
--- /dev/null
@@ -0,0 +1,1353 @@
+//! The Rust compiler.
+//!
+//! # Note
+//!
+//! This API is completely unstable and subject to change.
+
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(is_terminal)]
+#![feature(once_cell)]
+#![feature(decl_macro)]
+#![recursion_limit = "256"]
+#![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
+
+#[macro_use]
+extern crate tracing;
+
+pub extern crate rustc_plugin_impl as plugin;
+
+use rustc_ast as ast;
+use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults};
+use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
+use rustc_data_structures::sync::SeqCst;
+use rustc_errors::registry::{InvalidErrorCode, Registry};
+use rustc_errors::{ErrorGuaranteed, PResult};
+use rustc_feature::find_gated_cfg;
+use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
+use rustc_interface::{interface, Queries};
+use rustc_lint::LintStore;
+use rustc_metadata::locator;
+use rustc_save_analysis as save;
+use rustc_save_analysis::DumpHandler;
+use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
+use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
+use rustc_session::cstore::MetadataLoader;
+use rustc_session::getopts;
+use rustc_session::lint::{Lint, LintId};
+use rustc_session::{config, Session};
+use rustc_session::{early_error, early_error_no_abort, early_warn};
+use rustc_span::source_map::{FileLoader, FileName};
+use rustc_span::symbol::sym;
+use rustc_target::json::ToJson;
+
+use std::cmp::max;
+use std::env;
+use std::ffi::OsString;
+use std::fs;
+use std::io::{self, IsTerminal, Read, Write};
+use std::panic::{self, catch_unwind};
+use std::path::PathBuf;
+use std::process::{self, Command, Stdio};
+use std::str;
+use std::sync::LazyLock;
+use std::time::Instant;
+
+pub mod args;
+pub mod pretty;
+mod session_diagnostics;
+
+use crate::session_diagnostics::{
+    RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch,
+    RLinkWrongFileType, RlinkNotAFile, RlinkUnableToRead,
+};
+
+/// Exit status code used for successful compilation and help output.
+pub const EXIT_SUCCESS: i32 = 0;
+
+/// Exit status code used for compilation failures and invalid flags.
+pub const EXIT_FAILURE: i32 = 1;
+
+const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
+    ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
+
+const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["-Z", "-C", "--crate-type"];
+
+const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename"];
+
+const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &[&str] = &["incremental"];
+
+pub fn abort_on_err<T>(result: Result<T, ErrorGuaranteed>, sess: &Session) -> T {
+    match result {
+        Err(..) => {
+            sess.abort_if_errors();
+            panic!("error reported but abort_if_errors didn't abort???");
+        }
+        Ok(x) => x,
+    }
+}
+
+pub trait Callbacks {
+    /// Called before creating the compiler instance
+    fn config(&mut self, _config: &mut interface::Config) {}
+    /// Called after parsing. Return value instructs the compiler whether to
+    /// continue the compilation afterwards (defaults to `Compilation::Continue`)
+    fn after_parsing<'tcx>(
+        &mut self,
+        _compiler: &interface::Compiler,
+        _queries: &'tcx Queries<'tcx>,
+    ) -> Compilation {
+        Compilation::Continue
+    }
+    /// Called after expansion. Return value instructs the compiler whether to
+    /// continue the compilation afterwards (defaults to `Compilation::Continue`)
+    fn after_expansion<'tcx>(
+        &mut self,
+        _compiler: &interface::Compiler,
+        _queries: &'tcx Queries<'tcx>,
+    ) -> Compilation {
+        Compilation::Continue
+    }
+    /// Called after analysis. Return value instructs the compiler whether to
+    /// continue the compilation afterwards (defaults to `Compilation::Continue`)
+    fn after_analysis<'tcx>(
+        &mut self,
+        _compiler: &interface::Compiler,
+        _queries: &'tcx Queries<'tcx>,
+    ) -> Compilation {
+        Compilation::Continue
+    }
+}
+
+#[derive(Default)]
+pub struct TimePassesCallbacks {
+    time_passes: bool,
+}
+
+impl Callbacks for TimePassesCallbacks {
+    // JUSTIFICATION: the session doesn't exist at this point.
+    #[allow(rustc::bad_opt_access)]
+    fn config(&mut self, config: &mut interface::Config) {
+        // If a --print=... option has been given, we don't print the "total"
+        // time because it will mess up the --print output. See #64339.
+        //
+        self.time_passes = config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes;
+        config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath;
+    }
+}
+
+pub fn diagnostics_registry() -> Registry {
+    Registry::new(rustc_error_codes::DIAGNOSTICS)
+}
+
+/// This is the primary entry point for rustc.
+pub struct RunCompiler<'a, 'b> {
+    at_args: &'a [String],
+    callbacks: &'b mut (dyn Callbacks + Send),
+    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
+    make_codegen_backend:
+        Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
+}
+
+impl<'a, 'b> RunCompiler<'a, 'b> {
+    pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self {
+        Self { at_args, callbacks, file_loader: None, make_codegen_backend: None }
+    }
+
+    /// Set a custom codegen backend.
+    ///
+    /// Has no uses within this repository, but is used by bjorn3 for "the
+    /// hotswapping branch of cg_clif" for "setting the codegen backend from a
+    /// custom driver where the custom codegen backend has arbitrary data."
+    /// (See #102759.)
+    pub fn set_make_codegen_backend(
+        &mut self,
+        make_codegen_backend: Option<
+            Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
+        >,
+    ) -> &mut Self {
+        self.make_codegen_backend = make_codegen_backend;
+        self
+    }
+
+    /// Load files from sources other than the file system.
+    ///
+    /// Has no uses within this repository, but may be used in the future by
+    /// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for
+    /// running rustc without having to save". (See #102759.)
+    pub fn set_file_loader(
+        &mut self,
+        file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
+    ) -> &mut Self {
+        self.file_loader = file_loader;
+        self
+    }
+
+    /// Parse args and run the compiler.
+    pub fn run(self) -> interface::Result<()> {
+        run_compiler(self.at_args, self.callbacks, self.file_loader, self.make_codegen_backend)
+    }
+}
+
+fn run_compiler(
+    at_args: &[String],
+    callbacks: &mut (dyn Callbacks + Send),
+    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
+    make_codegen_backend: Option<
+        Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
+    >,
+) -> interface::Result<()> {
+    let args = args::arg_expand_all(at_args);
+
+    let Some(matches) = handle_options(&args) else { return Ok(()) };
+
+    let sopts = config::build_session_options(&matches);
+
+    if let Some(ref code) = matches.opt_str("explain") {
+        handle_explain(diagnostics_registry(), code, sopts.error_format);
+        return Ok(());
+    }
+
+    let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
+    let check_cfg = interface::parse_check_cfg(matches.opt_strs("check-cfg"));
+    let (odir, ofile) = make_output(&matches);
+    let mut config = interface::Config {
+        opts: sopts,
+        crate_cfg: cfg,
+        crate_check_cfg: check_cfg,
+        input: Input::File(PathBuf::new()),
+        output_file: ofile,
+        output_dir: odir,
+        file_loader,
+        lint_caps: Default::default(),
+        parse_sess_created: None,
+        register_lints: None,
+        override_queries: None,
+        make_codegen_backend,
+        registry: diagnostics_registry(),
+    };
+
+    if !tracing::dispatcher::has_been_set() {
+        init_rustc_env_logger_with_backtrace_option(&config.opts.unstable_opts.log_backtrace);
+    }
+
+    match make_input(config.opts.error_format, &matches.free) {
+        Err(reported) => return Err(reported),
+        Ok(Some(input)) => {
+            config.input = input;
+
+            callbacks.config(&mut config);
+        }
+        Ok(None) => match matches.free.len() {
+            0 => {
+                callbacks.config(&mut config);
+                interface::run_compiler(config, |compiler| {
+                    let sopts = &compiler.session().opts;
+                    if sopts.describe_lints {
+                        let mut lint_store =
+                            rustc_lint::new_lint_store(compiler.session().enable_internal_lints());
+                        let registered_lints =
+                            if let Some(register_lints) = compiler.register_lints() {
+                                register_lints(compiler.session(), &mut lint_store);
+                                true
+                            } else {
+                                false
+                            };
+                        describe_lints(compiler.session(), &lint_store, registered_lints);
+                        return;
+                    }
+                    let should_stop =
+                        print_crate_info(&***compiler.codegen_backend(), compiler.session(), false);
+
+                    if should_stop == Compilation::Stop {
+                        return;
+                    }
+                    early_error(sopts.error_format, "no input filename given")
+                });
+                return Ok(());
+            }
+            1 => panic!("make_input should have provided valid inputs"),
+            _ => early_error(
+                config.opts.error_format,
+                &format!(
+                    "multiple input filenames provided (first two filenames are `{}` and `{}`)",
+                    matches.free[0], matches.free[1],
+                ),
+            ),
+        },
+    };
+
+    interface::run_compiler(config, |compiler| {
+        let sess = compiler.session();
+        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();
+        }
+
+        let linker = compiler.enter(|queries| {
+            let early_exit = || sess.compile_status().map(|_| None);
+            queries.parse()?;
+
+            if let Some(ppm) = &sess.opts.pretty {
+                if ppm.needs_ast_map() {
+                    queries.global_ctxt()?.enter(|tcx| {
+                        pretty::print_after_hir_lowering(tcx, *ppm);
+                        Ok(())
+                    })?;
+                } else {
+                    let krate = queries.parse()?.steal();
+                    pretty::print_after_parsing(sess, &krate, *ppm);
+                }
+                trace!("finished pretty-printing");
+                return early_exit();
+            }
+
+            if callbacks.after_parsing(compiler, queries) == Compilation::Stop {
+                return early_exit();
+            }
+
+            if sess.opts.unstable_opts.parse_only || sess.opts.unstable_opts.show_span.is_some() {
+                return early_exit();
+            }
+
+            {
+                let plugins = queries.register_plugins()?;
+                let (_, lint_store) = &*plugins.borrow();
+
+                // Lint plugins are registered; now we can process command line flags.
+                if sess.opts.describe_lints {
+                    describe_lints(sess, lint_store, true);
+                    return early_exit();
+                }
+            }
+
+            // Make sure name resolution and macro expansion is run.
+            queries.global_ctxt()?;
+
+            if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
+                return early_exit();
+            }
+
+            // Make sure the `output_filenames` query is run for its side
+            // effects of writing the dep-info and reporting errors.
+            queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(()));
+
+            if sess.opts.output_types.contains_key(&OutputType::DepInfo)
+                && sess.opts.output_types.len() == 1
+            {
+                return early_exit();
+            }
+
+            if sess.opts.unstable_opts.no_analysis {
+                return early_exit();
+            }
+
+            queries.global_ctxt()?.enter(|tcx| {
+                let result = tcx.analysis(());
+                if sess.opts.unstable_opts.save_analysis {
+                    let crate_name = tcx.crate_name(LOCAL_CRATE);
+                    sess.time("save_analysis", || {
+                        save::process_crate(
+                            tcx,
+                            crate_name,
+                            &sess.io.input,
+                            None,
+                            DumpHandler::new(sess.io.output_dir.as_deref(), crate_name),
+                        )
+                    });
+                }
+                result
+            })?;
+
+            if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
+                return early_exit();
+            }
+
+            queries.ongoing_codegen()?;
+
+            if sess.opts.unstable_opts.print_type_sizes {
+                sess.code_stats.print_type_sizes();
+            }
+
+            let linker = queries.linker()?;
+            Ok(Some(linker))
+        })?;
+
+        if let Some(linker) = linker {
+            let _timer = sess.timer("link");
+            linker.link()?
+        }
+
+        if sess.opts.unstable_opts.perf_stats {
+            sess.print_perf_stats();
+        }
+
+        if sess.opts.unstable_opts.print_fuel.is_some() {
+            eprintln!(
+                "Fuel used by {}: {}",
+                sess.opts.unstable_opts.print_fuel.as_ref().unwrap(),
+                sess.print_fuel.load(SeqCst)
+            );
+        }
+
+        Ok(())
+    })
+}
+
+// Extract output directory and file from matches.
+fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
+    let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
+    let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o));
+    (odir, ofile)
+}
+
+// Extract input (string or file and optional path) from matches.
+fn make_input(
+    error_format: ErrorOutputType,
+    free_matches: &[String],
+) -> Result<Option<Input>, ErrorGuaranteed> {
+    if free_matches.len() == 1 {
+        let ifile = &free_matches[0];
+        if ifile == "-" {
+            let mut src = String::new();
+            if io::stdin().read_to_string(&mut src).is_err() {
+                // Immediately stop compilation if there was an issue reading
+                // the input (for example if the input stream is not UTF-8).
+                let reported = early_error_no_abort(
+                    error_format,
+                    "couldn't read from stdin, as it did not contain valid UTF-8",
+                );
+                return Err(reported);
+            }
+            if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
+                let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
+                    "when UNSTABLE_RUSTDOC_TEST_PATH is set \
+                                    UNSTABLE_RUSTDOC_TEST_LINE also needs to be set",
+                );
+                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 }))
+            } else {
+                Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src }))
+            }
+        } else {
+            Ok(Some(Input::File(PathBuf::from(ifile))))
+        }
+    } else {
+        Ok(None)
+    }
+}
+
+/// Whether to stop or continue compilation.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Compilation {
+    Stop,
+    Continue,
+}
+
+impl Compilation {
+    pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
+        match self {
+            Compilation::Stop => Compilation::Stop,
+            Compilation::Continue => next(),
+        }
+    }
+}
+
+fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
+    let upper_cased_code = code.to_ascii_uppercase();
+    let normalised =
+        if upper_cased_code.starts_with('E') { upper_cased_code } else { format!("E{code:0>4}") };
+    match registry.try_find_description(&normalised) {
+        Ok(Some(description)) => {
+            let mut is_in_code_block = false;
+            let mut text = String::new();
+            // Slice off the leading newline and print.
+            for line in description.lines() {
+                let indent_level =
+                    line.find(|c: char| !c.is_whitespace()).unwrap_or_else(|| line.len());
+                let dedented_line = &line[indent_level..];
+                if dedented_line.starts_with("```") {
+                    is_in_code_block = !is_in_code_block;
+                    text.push_str(&line[..(indent_level + 3)]);
+                } else if is_in_code_block && dedented_line.starts_with("# ") {
+                    continue;
+                } else {
+                    text.push_str(line);
+                }
+                text.push('\n');
+            }
+            if io::stdout().is_terminal() {
+                show_content_with_pager(&text);
+            } else {
+                print!("{text}");
+            }
+        }
+        Ok(None) => {
+            early_error(output, &format!("no extended information for {code}"));
+        }
+        Err(InvalidErrorCode) => {
+            early_error(output, &format!("{code} is not a valid error code"));
+        }
+    }
+}
+
+fn show_content_with_pager(content: &str) {
+    let pager_name = env::var_os("PAGER").unwrap_or_else(|| {
+        if cfg!(windows) { OsString::from("more.com") } else { OsString::from("less") }
+    });
+
+    let mut fallback_to_println = false;
+
+    match Command::new(pager_name).stdin(Stdio::piped()).spawn() {
+        Ok(mut pager) => {
+            if let Some(pipe) = pager.stdin.as_mut() {
+                if pipe.write_all(content.as_bytes()).is_err() {
+                    fallback_to_println = true;
+                }
+            }
+
+            if pager.wait().is_err() {
+                fallback_to_println = true;
+            }
+        }
+        Err(_) => {
+            fallback_to_println = true;
+        }
+    }
+
+    // If pager fails for whatever reason, we should still print the content
+    // to standard output
+    if fallback_to_println {
+        print!("{content}");
+    }
+}
+
+pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
+    if sess.opts.unstable_opts.link_only {
+        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, &[]);
+            let rlink_data = fs::read(file).unwrap_or_else(|err| {
+                sess.emit_fatal(RlinkUnableToRead { err });
+            });
+            let codegen_results = match CodegenResults::deserialize_rlink(rlink_data) {
+                Ok(codegen) => codegen,
+                Err(err) => {
+                    match err {
+                        CodegenErrors::WrongFileType => sess.emit_fatal(RLinkWrongFileType),
+                        CodegenErrors::EmptyVersionNumber => {
+                            sess.emit_fatal(RLinkEmptyVersionNumber)
+                        }
+                        CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => {
+                            sess.emit_fatal(RLinkEncodingVersionMismatch {
+                                version_array,
+                                rlink_version,
+                            })
+                        }
+                        CodegenErrors::RustcVersionMismatch { rustc_version, current_version } => {
+                            sess.emit_fatal(RLinkRustcVersionMismatch {
+                                rustc_version,
+                                current_version,
+                            })
+                        }
+                    };
+                }
+            };
+            let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
+            abort_on_err(result, sess);
+        } else {
+            sess.emit_fatal(RlinkNotAFile {})
+        }
+        Compilation::Stop
+    } else {
+        Compilation::Continue
+    }
+}
+
+pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Compilation {
+    if sess.opts.unstable_opts.ls {
+        match sess.io.input {
+            Input::File(ref ifile) => {
+                let path = &(*ifile);
+                let mut v = Vec::new();
+                locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v).unwrap();
+                println!("{}", String::from_utf8(v).unwrap());
+            }
+            Input::Str { .. } => {
+                early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
+            }
+        }
+        return Compilation::Stop;
+    }
+
+    Compilation::Continue
+}
+
+fn print_crate_info(
+    codegen_backend: &dyn CodegenBackend,
+    sess: &Session,
+    parse_attrs: bool,
+) -> Compilation {
+    use rustc_session::config::PrintRequest::*;
+    // NativeStaticLibs and LinkArgs are special - printed during linking
+    // (empty iterator returns true)
+    if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) {
+        return Compilation::Continue;
+    }
+
+    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 {
+            TargetList => {
+                let mut targets = rustc_target::spec::TARGETS.to_vec();
+                targets.sort_unstable();
+                println!("{}", targets.join("\n"));
+            }
+            Sysroot => println!("{}", sess.sysroot.display()),
+            TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
+            TargetSpec => {
+                println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
+            }
+            FileNames | CrateName => {
+                let attrs = attrs.as_ref().unwrap();
+                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;
+                }
+                let crate_types = collect_crate_types(sess, attrs);
+                for &style in &crate_types {
+                    let fname =
+                        rustc_session::output::filename_for_input(sess, style, id, &t_outputs);
+                    println!("{}", fname.file_name().unwrap().to_string_lossy());
+                }
+            }
+            Cfg => {
+                let mut cfgs = sess
+                    .parse_sess
+                    .config
+                    .iter()
+                    .filter_map(|&(name, value)| {
+                        // Note that crt-static is a specially recognized cfg
+                        // directive that's printed out here as part of
+                        // rust-lang/rust#37406, but in general the
+                        // `target_feature` cfg is gated under
+                        // rust-lang/rust#29717. For now this is just
+                        // specifically allowing the crt-static cfg and that's
+                        // it, this is intended to get into Cargo and then go
+                        // through to build scripts.
+                        if (name != sym::target_feature || value != Some(sym::crt_dash_static))
+                            && !sess.is_nightly_build()
+                            && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
+                        {
+                            return None;
+                        }
+
+                        if let Some(value) = value {
+                            Some(format!("{name}=\"{value}\""))
+                        } else {
+                            Some(name.to_string())
+                        }
+                    })
+                    .collect::<Vec<String>>();
+
+                cfgs.sort();
+                for cfg in cfgs {
+                    println!("{cfg}");
+                }
+            }
+            CallingConventions => {
+                let mut calling_conventions = rustc_target::spec::abi::all_names();
+                calling_conventions.sort_unstable();
+                println!("{}", calling_conventions.join("\n"));
+            }
+            RelocationModels
+            | CodeModels
+            | TlsModels
+            | TargetCPUs
+            | StackProtectorStrategies
+            | TargetFeatures => {
+                codegen_backend.print(*req, sess);
+            }
+            // Any output here interferes with Cargo's parsing of other printed output
+            NativeStaticLibs => {}
+            LinkArgs => {}
+            SplitDebuginfo => {
+                use rustc_target::spec::SplitDebuginfo::{Off, Packed, Unpacked};
+
+                for split in &[Off, Packed, Unpacked] {
+                    let stable = sess.target.options.supported_split_debuginfo.contains(split);
+                    let unstable_ok = sess.unstable_options();
+                    if stable || unstable_ok {
+                        println!("{split}");
+                    }
+                }
+            }
+        }
+    }
+    Compilation::Stop
+}
+
+/// Prints version information
+///
+/// NOTE: this is a macro to support drivers built at a different time than the main `rustc_driver` crate.
+pub macro version($binary: literal, $matches: expr) {
+    fn unw(x: Option<&str>) -> &str {
+        x.unwrap_or("unknown")
+    }
+    $crate::version_at_macro_invocation(
+        $binary,
+        $matches,
+        unw(option_env!("CFG_VERSION")),
+        unw(option_env!("CFG_VER_HASH")),
+        unw(option_env!("CFG_VER_DATE")),
+        unw(option_env!("CFG_RELEASE")),
+    )
+}
+
+#[doc(hidden)] // use the macro instead
+pub fn version_at_macro_invocation(
+    binary: &str,
+    matches: &getopts::Matches,
+    version: &str,
+    commit_hash: &str,
+    commit_date: &str,
+    release: &str,
+) {
+    let verbose = matches.opt_present("verbose");
+
+    println!("{binary} {version}");
+
+    if verbose {
+        println!("binary: {binary}");
+        println!("commit-hash: {commit_hash}");
+        println!("commit-date: {commit_date}");
+        println!("host: {}", config::host_triple());
+        println!("release: {release}");
+
+        let debug_flags = matches.opt_strs("Z");
+        let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
+        get_codegen_backend(&None, backend_name).print_version();
+    }
+}
+
+fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
+    let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() };
+    let mut options = getopts::Options::new();
+    for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
+        (option.apply)(&mut options);
+    }
+    let message = "Usage: rustc [OPTIONS] INPUT";
+    let nightly_help = if nightly_build {
+        "\n    -Z help             Print unstable compiler options"
+    } else {
+        ""
+    };
+    let verbose_help = if verbose {
+        ""
+    } else {
+        "\n    --help -v           Print the full set of options rustc accepts"
+    };
+    let at_path = if verbose {
+        "    @path               Read newline separated options from `path`\n"
+    } else {
+        ""
+    };
+    println!(
+        "{options}{at_path}\nAdditional help:
+    -C help             Print codegen options
+    -W help             \
+              Print 'lint' options and default settings{nightly}{verbose}\n",
+        options = options.usage(message),
+        at_path = at_path,
+        nightly = nightly_help,
+        verbose = verbose_help
+    );
+}
+
+fn print_wall_help() {
+    println!(
+        "
+The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by
+default. Use `rustc -W help` to see all available lints. It's more common to put
+warning settings in the crate root using `#![warn(LINT_NAME)]` instead of using
+the command line flag directly.
+"
+    );
+}
+
+/// Write to stdout lint command options, together with a list of all available lints
+pub fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) {
+    println!(
+        "
+Available lint options:
+    -W <foo>           Warn about <foo>
+    -A <foo>           \
+              Allow <foo>
+    -D <foo>           Deny <foo>
+    -F <foo>           Forbid <foo> \
+              (deny <foo> and all attempts to override)
+
+"
+    );
+
+    fn sort_lints(sess: &Session, mut lints: Vec<&'static Lint>) -> Vec<&'static Lint> {
+        // The sort doesn't case-fold but it's doubtful we care.
+        lints.sort_by_cached_key(|x: &&Lint| (x.default_level(sess.edition()), x.name));
+        lints
+    }
+
+    fn sort_lint_groups(
+        lints: Vec<(&'static str, Vec<LintId>, bool)>,
+    ) -> Vec<(&'static str, Vec<LintId>)> {
+        let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
+        lints.sort_by_key(|l| l.0);
+        lints
+    }
+
+    let (plugin, builtin): (Vec<_>, _) =
+        lint_store.get_lints().iter().cloned().partition(|&lint| lint.is_plugin);
+    let plugin = sort_lints(sess, plugin);
+    let builtin = sort_lints(sess, builtin);
+
+    let (plugin_groups, builtin_groups): (Vec<_>, _) =
+        lint_store.get_lint_groups().partition(|&(.., p)| p);
+    let plugin_groups = sort_lint_groups(plugin_groups);
+    let builtin_groups = sort_lint_groups(builtin_groups);
+
+    let max_name_len =
+        plugin.iter().chain(&builtin).map(|&s| s.name.chars().count()).max().unwrap_or(0);
+    let padded = |x: &str| {
+        let mut s = " ".repeat(max_name_len - x.chars().count());
+        s.push_str(x);
+        s
+    };
+
+    println!("Lint checks provided by rustc:\n");
+
+    let print_lints = |lints: Vec<&Lint>| {
+        println!("    {}  {:7.7}  {}", padded("name"), "default", "meaning");
+        println!("    {}  {:7.7}  {}", padded("----"), "-------", "-------");
+        for lint in lints {
+            let name = lint.name_lower().replace('_', "-");
+            println!(
+                "    {}  {:7.7}  {}",
+                padded(&name),
+                lint.default_level(sess.edition()).as_str(),
+                lint.desc
+            );
+        }
+        println!("\n");
+    };
+
+    print_lints(builtin);
+
+    let max_name_len = max(
+        "warnings".len(),
+        plugin_groups
+            .iter()
+            .chain(&builtin_groups)
+            .map(|&(s, _)| s.chars().count())
+            .max()
+            .unwrap_or(0),
+    );
+
+    let padded = |x: &str| {
+        let mut s = " ".repeat(max_name_len - x.chars().count());
+        s.push_str(x);
+        s
+    };
+
+    println!("Lint groups provided by rustc:\n");
+
+    let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>, all_warnings| {
+        println!("    {}  sub-lints", padded("name"));
+        println!("    {}  ---------", padded("----"));
+
+        if all_warnings {
+            println!("    {}  all lints that are set to issue warnings", padded("warnings"));
+        }
+
+        for (name, to) in lints {
+            let name = name.to_lowercase().replace('_', "-");
+            let desc = to
+                .into_iter()
+                .map(|x| x.to_string().replace('_', "-"))
+                .collect::<Vec<String>>()
+                .join(", ");
+            println!("    {}  {}", padded(&name), desc);
+        }
+        println!("\n");
+    };
+
+    print_lint_groups(builtin_groups, true);
+
+    match (loaded_plugins, plugin.len(), plugin_groups.len()) {
+        (false, 0, _) | (false, _, 0) => {
+            println!("Lint tools like Clippy can provide additional lints and lint groups.");
+        }
+        (false, ..) => panic!("didn't load lint plugins but got them anyway!"),
+        (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
+        (true, l, g) => {
+            if l > 0 {
+                println!("Lint checks provided by plugins loaded by this crate:\n");
+                print_lints(plugin);
+            }
+            if g > 0 {
+                println!("Lint groups provided by plugins loaded by this crate:\n");
+                print_lint_groups(plugin_groups, false);
+            }
+        }
+    }
+}
+
+fn describe_debug_flags() {
+    println!("\nAvailable options:\n");
+    print_flag_list("-Z", config::Z_OPTIONS);
+}
+
+fn describe_codegen_flags() {
+    println!("\nAvailable codegen options:\n");
+    print_flag_list("-C", config::CG_OPTIONS);
+}
+
+pub fn print_flag_list<T>(
+    cmdline_opt: &str,
+    flag_list: &[(&'static str, T, &'static str, &'static str)],
+) {
+    let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0);
+
+    for &(name, _, _, desc) in flag_list {
+        println!(
+            "    {} {:>width$}=val -- {}",
+            cmdline_opt,
+            name.replace('_', "-"),
+            desc,
+            width = max_len
+        );
+    }
+}
+
+/// Process command line options. Emits messages as appropriate. If compilation
+/// should continue, returns a getopts::Matches object parsed from args,
+/// otherwise returns `None`.
+///
+/// The compiler's handling of options is a little complicated as it ties into
+/// our stability story. The current intention of each compiler option is to
+/// have one of two modes:
+///
+/// 1. An option is stable and can be used everywhere.
+/// 2. An option is unstable, and can only be used on nightly.
+///
+/// Like unstable library and language features, however, unstable options have
+/// always required a form of "opt in" to indicate that you're using them. This
+/// provides the easy ability to scan a code base to check to see if anything
+/// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
+///
+/// All options behind `-Z` are considered unstable by default. Other top-level
+/// options can also be considered unstable, and they were unlocked through the
+/// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
+/// instability in both cases, though.
+///
+/// So with all that in mind, the comments below have some more detail about the
+/// contortions done here to get things to work out correctly.
+pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
+    // Throw away the first argument, the name of the binary
+    let args = &args[1..];
+
+    if args.is_empty() {
+        // user did not write `-v` nor `-Z unstable-options`, so do not
+        // include that extra information.
+        let nightly_build =
+            rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build();
+        usage(false, false, nightly_build);
+        return None;
+    }
+
+    // Parse with *all* options defined in the compiler, we don't worry about
+    // option stability here we just want to parse as much as possible.
+    let mut options = getopts::Options::new();
+    for option in config::rustc_optgroups() {
+        (option.apply)(&mut options);
+    }
+    let matches = options.parse(args).unwrap_or_else(|e| {
+        let msg = match e {
+            getopts::Fail::UnrecognizedOption(ref opt) => CG_OPTIONS
+                .iter()
+                .map(|&(name, ..)| ('C', name))
+                .chain(Z_OPTIONS.iter().map(|&(name, ..)| ('Z', name)))
+                .find(|&(_, name)| *opt == name.replace('_', "-"))
+                .map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")),
+            _ => None,
+        };
+        early_error(ErrorOutputType::default(), &msg.unwrap_or_else(|| e.to_string()));
+    });
+
+    // For all options we just parsed, we check a few aspects:
+    //
+    // * If the option is stable, we're all good
+    // * If the option wasn't passed, we're all good
+    // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
+    //   ourselves), then we require the `-Z unstable-options` flag to unlock
+    //   this option that was passed.
+    // * If we're a nightly compiler, then unstable options are now unlocked, so
+    //   we're good to go.
+    // * Otherwise, if we're an unstable option then we generate an error
+    //   (unstable option being used on stable)
+    nightly_options::check_nightly_options(&matches, &config::rustc_optgroups());
+
+    if matches.opt_present("h") || matches.opt_present("help") {
+        // Only show unstable options in --help if we accept unstable options.
+        let unstable_enabled = nightly_options::is_unstable_enabled(&matches);
+        let nightly_build = nightly_options::match_is_nightly_build(&matches);
+        usage(matches.opt_present("verbose"), unstable_enabled, nightly_build);
+        return None;
+    }
+
+    // Handle the special case of -Wall.
+    let wall = matches.opt_strs("W");
+    if wall.iter().any(|x| *x == "all") {
+        print_wall_help();
+        rustc_errors::FatalError.raise();
+    }
+
+    // Don't handle -W help here, because we might first load plugins.
+    let debug_flags = matches.opt_strs("Z");
+    if debug_flags.iter().any(|x| *x == "help") {
+        describe_debug_flags();
+        return None;
+    }
+
+    let cg_flags = matches.opt_strs("C");
+
+    if cg_flags.iter().any(|x| *x == "help") {
+        describe_codegen_flags();
+        return None;
+    }
+
+    if cg_flags.iter().any(|x| *x == "no-stack-check") {
+        early_warn(
+            ErrorOutputType::default(),
+            "the --no-stack-check flag is deprecated and does nothing",
+        );
+    }
+
+    if cg_flags.iter().any(|x| *x == "passes=list") {
+        let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
+        get_codegen_backend(&None, backend_name).print_passes();
+        return None;
+    }
+
+    if matches.opt_present("version") {
+        version!("rustc", &matches);
+        return None;
+    }
+
+    Some(matches)
+}
+
+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(),
+            input.clone(),
+            &sess.parse_sess,
+        ),
+    }
+}
+
+/// Gets a list of extra command-line flags provided by the user, as strings.
+///
+/// This function is used during ICEs to show more information useful for
+/// debugging, since some ICEs only happens with non-default compiler flags
+/// (and the users don't always report them).
+fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
+    let mut args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).peekable();
+
+    let mut result = Vec::new();
+    let mut excluded_cargo_defaults = false;
+    while let Some(arg) = args.next() {
+        if let Some(a) = ICE_REPORT_COMPILER_FLAGS.iter().find(|a| arg.starts_with(*a)) {
+            let content = if arg.len() == a.len() {
+                // A space-separated option, like `-C incremental=foo` or `--crate-type rlib`
+                match args.next() {
+                    Some(arg) => arg.to_string(),
+                    None => continue,
+                }
+            } else if arg.get(a.len()..a.len() + 1) == Some("=") {
+                // An equals option, like `--crate-type=rlib`
+                arg[a.len() + 1..].to_string()
+            } else {
+                // A non-space option, like `-Cincremental=foo`
+                arg[a.len()..].to_string()
+            };
+            let option = content.split_once('=').map(|s| s.0).unwrap_or(&content);
+            if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| option == *exc) {
+                excluded_cargo_defaults = true;
+            } else {
+                result.push(a.to_string());
+                match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| option == **s) {
+                    Some(s) => result.push(format!("{s}=[REDACTED]")),
+                    None => result.push(content),
+                }
+            }
+        }
+    }
+
+    if !result.is_empty() { Some((result, excluded_cargo_defaults)) } else { None }
+}
+
+/// Runs a closure and catches unwinds triggered by fatal errors.
+///
+/// The compiler currently unwinds with a special sentinel value to abort
+/// compilation on fatal errors. This function catches that sentinel and turns
+/// the panic into a `Result` instead.
+pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorGuaranteed> {
+    catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
+        if value.is::<rustc_errors::FatalErrorMarker>() {
+            ErrorGuaranteed::unchecked_claim_error_was_emitted()
+        } else {
+            panic::resume_unwind(value);
+        }
+    })
+}
+
+/// Variant of `catch_fatal_errors` for the `interface::Result` return type
+/// that also computes the exit code.
+pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
+    let result = catch_fatal_errors(f).and_then(|result| result);
+    match result {
+        Ok(()) => EXIT_SUCCESS,
+        Err(_) => EXIT_FAILURE,
+    }
+}
+
+static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
+    LazyLock::new(|| {
+        let hook = panic::take_hook();
+        panic::set_hook(Box::new(|info| {
+            // If the error was caused by a broken pipe then this is not a bug.
+            // Write the error and return immediately. See #98700.
+            #[cfg(windows)]
+            if let Some(msg) = info.payload().downcast_ref::<String>() {
+                if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)")
+                {
+                    early_error_no_abort(ErrorOutputType::default(), &msg);
+                    return;
+                }
+            };
+
+            // Invoke the default handler, which prints the actual panic message and optionally a backtrace
+            // Don't do this for delayed bugs, which already emit their own more useful backtrace.
+            if !info.payload().is::<rustc_errors::DelayedBugPanic>() {
+                (*DEFAULT_HOOK)(info);
+
+                // Separate the output with an empty line
+                eprintln!();
+            }
+
+            // Print the ICE message
+            report_ice(info, BUG_REPORT_URL);
+        }));
+        hook
+    });
+
+/// Prints the ICE message, including query stack, but without backtrace.
+///
+/// The message will point the user at `bug_report_url` to report the ICE.
+///
+/// When `install_ice_hook` is called, this function will be called as the panic
+/// hook.
+pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
+    let fallback_bundle =
+        rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
+        rustc_errors::ColorConfig::Auto,
+        None,
+        None,
+        fallback_bundle,
+        false,
+        false,
+        None,
+        false,
+        false,
+    ));
+    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
+
+    // a .span_bug or .bug call has already printed what
+    // it wants to print.
+    if !info.payload().is::<rustc_errors::ExplicitBug>()
+        && !info.payload().is::<rustc_errors::DelayedBugPanic>()
+    {
+        let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
+        handler.emit_diagnostic(&mut d);
+    }
+
+    handler.emit_note(session_diagnostics::Ice);
+    handler.emit_note(session_diagnostics::IceBugReport { bug_report_url });
+    handler.emit_note(session_diagnostics::IceVersion {
+        version: util::version_str!().unwrap_or("unknown_version"),
+        triple: config::host_triple(),
+    });
+
+    if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
+        handler.emit_note(session_diagnostics::IceFlags { flags: flags.join(" ") });
+        if excluded_cargo_defaults {
+            handler.emit_note(session_diagnostics::IceExcludeCargoDefaults);
+        }
+    }
+
+    // If backtraces are enabled, also print the query stack
+    let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");
+
+    let num_frames = if backtrace { None } else { Some(2) };
+
+    interface::try_print_query_stack(&handler, num_frames);
+
+    #[cfg(windows)]
+    unsafe {
+        if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
+            // Trigger a debugger if we crashed during bootstrap
+            winapi::um::debugapi::DebugBreak();
+        }
+    }
+}
+
+/// Installs a panic hook that will print the ICE message on unexpected panics.
+///
+/// A custom rustc driver can skip calling this to set up a custom ICE hook.
+pub fn install_ice_hook() {
+    // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
+    // full backtraces. When a compiler ICE happens, we want to gather
+    // as much information as possible to present in the issue opened
+    // by the user. Compiler developers and other rustc users can
+    // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
+    // (e.g. `RUST_BACKTRACE=1`)
+    if std::env::var("RUST_BACKTRACE").is_err() {
+        std::env::set_var("RUST_BACKTRACE", "full");
+    }
+    LazyLock::force(&DEFAULT_HOOK);
+}
+
+/// This allows tools to enable rust logging without having to magically match rustc's
+/// tracing crate version.
+pub fn init_rustc_env_logger() {
+    init_rustc_env_logger_with_backtrace_option(&None);
+}
+
+/// This allows tools to enable rust logging without having to magically match rustc's
+/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to
+/// choose a target module you wish to show backtraces along with its logging.
+pub fn init_rustc_env_logger_with_backtrace_option(backtrace_target: &Option<String>) {
+    if let Err(error) = rustc_log::init_rustc_env_logger_with_backtrace_option(backtrace_target) {
+        early_error(ErrorOutputType::default(), &error.to_string());
+    }
+}
+
+/// This allows tools to enable rust logging without having to magically match rustc's
+/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
+/// other than `RUSTC_LOG`.
+pub fn init_env_logger(env: &str) {
+    if let Err(error) = rustc_log::init_env_logger(env) {
+        early_error(ErrorOutputType::default(), &error.to_string());
+    }
+}
+
+#[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))]
+mod signal_handler {
+    extern "C" {
+        fn backtrace_symbols_fd(
+            buffer: *const *mut libc::c_void,
+            size: libc::c_int,
+            fd: libc::c_int,
+        );
+    }
+
+    extern "C" fn print_stack_trace(_: libc::c_int) {
+        const MAX_FRAMES: usize = 256;
+        static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] =
+            [std::ptr::null_mut(); MAX_FRAMES];
+        unsafe {
+            let depth = libc::backtrace(STACK_TRACE.as_mut_ptr(), MAX_FRAMES as i32);
+            if depth == 0 {
+                return;
+            }
+            backtrace_symbols_fd(STACK_TRACE.as_ptr(), depth, 2);
+        }
+    }
+
+    /// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
+    /// process, print a stack trace and then exit.
+    pub(super) fn install() {
+        unsafe {
+            const ALT_STACK_SIZE: usize = libc::MINSIGSTKSZ + 64 * 1024;
+            let mut alt_stack: libc::stack_t = std::mem::zeroed();
+            alt_stack.ss_sp =
+                std::alloc::alloc(std::alloc::Layout::from_size_align(ALT_STACK_SIZE, 1).unwrap())
+                    as *mut libc::c_void;
+            alt_stack.ss_size = ALT_STACK_SIZE;
+            libc::sigaltstack(&alt_stack, std::ptr::null_mut());
+
+            let mut sa: libc::sigaction = std::mem::zeroed();
+            sa.sa_sigaction = print_stack_trace as libc::sighandler_t;
+            sa.sa_flags = libc::SA_NODEFER | libc::SA_RESETHAND | libc::SA_ONSTACK;
+            libc::sigemptyset(&mut sa.sa_mask);
+            libc::sigaction(libc::SIGSEGV, &sa, std::ptr::null_mut());
+        }
+    }
+}
+
+#[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))]
+mod signal_handler {
+    pub(super) fn install() {}
+}
+
+pub fn main() -> ! {
+    let start_time = Instant::now();
+    let start_rss = get_resident_set_size();
+    signal_handler::install();
+    let mut callbacks = TimePassesCallbacks::default();
+    install_ice_hook();
+    let exit_code = catch_with_exit_code(|| {
+        let args = env::args_os()
+            .enumerate()
+            .map(|(i, arg)| {
+                arg.into_string().unwrap_or_else(|arg| {
+                    early_error(
+                        ErrorOutputType::default(),
+                        &format!("argument {i} is not valid Unicode: {arg:?}"),
+                    )
+                })
+            })
+            .collect::<Vec<_>>();
+        RunCompiler::new(&args, &mut callbacks).run()
+    });
+
+    if callbacks.time_passes {
+        let end_rss = get_resident_set_size();
+        print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss);
+    }
+
+    process::exit(exit_code)
+}
diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs
new file mode 100644 (file)
index 0000000..446c683
--- /dev/null
@@ -0,0 +1,522 @@
+//! The various pretty-printing routines.
+
+use crate::session_diagnostics::UnprettyDumpFail;
+use rustc_ast as ast;
+use rustc_ast_pretty::pprust;
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir as hir;
+use rustc_hir_pretty as pprust_hir;
+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::{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;
+
+pub use self::PpMode::*;
+pub use self::PpSourceMode::*;
+use crate::abort_on_err;
+
+// This slightly awkward construction is to allow for each PpMode to
+// choose whether it needs to do analyses (which can consume the
+// Session) and then pass through the session (now attached to the
+// analysis results) on to the chosen pretty-printer, along with the
+// `&PpAnn` object.
+//
+// Note that since the `&PrinterSupport` is freshly constructed on each
+// call, it would not make sense to try to attach the lifetime of `self`
+// to the lifetime of the `&PrinterObject`.
+
+/// Constructs a `PrinterSupport` object and passes it to `f`.
+fn call_with_pp_support<'tcx, A, F>(
+    ppmode: &PpSourceMode,
+    sess: &'tcx Session,
+    tcx: Option<TyCtxt<'tcx>>,
+    f: F,
+) -> A
+where
+    F: FnOnce(&dyn PrinterSupport) -> A,
+{
+    match *ppmode {
+        Normal | Expanded => {
+            let annotation = NoAnn { sess, tcx };
+            f(&annotation)
+        }
+
+        Identified | ExpandedIdentified => {
+            let annotation = IdentifiedAnnotation { sess, tcx };
+            f(&annotation)
+        }
+        ExpandedHygiene => {
+            let annotation = HygieneAnnotation { sess };
+            f(&annotation)
+        }
+    }
+}
+fn call_with_pp_support_hir<A, F>(ppmode: &PpHirMode, tcx: TyCtxt<'_>, f: F) -> A
+where
+    F: FnOnce(&dyn HirPrinterSupport<'_>, hir_map::Map<'_>) -> A,
+{
+    match *ppmode {
+        PpHirMode::Normal => {
+            let annotation = NoAnn { sess: tcx.sess, tcx: Some(tcx) };
+            f(&annotation, tcx.hir())
+        }
+
+        PpHirMode::Identified => {
+            let annotation = IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) };
+            f(&annotation, tcx.hir())
+        }
+        PpHirMode::Typed => {
+            abort_on_err(tcx.analysis(()), tcx.sess);
+
+            let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) };
+            tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir()))
+        }
+    }
+}
+
+trait PrinterSupport: pprust::PpAnn {
+    /// Provides a uniform interface for re-extracting a reference to a
+    /// `Session` from a value that now owns it.
+    fn sess(&self) -> &Session;
+
+    /// Produces the pretty-print annotation object.
+    ///
+    /// (Rust does not yet support upcasting from a trait object to
+    /// an object for one of its supertraits.)
+    fn pp_ann(&self) -> &dyn pprust::PpAnn;
+}
+
+trait HirPrinterSupport<'hir>: pprust_hir::PpAnn {
+    /// Provides a uniform interface for re-extracting a reference to a
+    /// `Session` from a value that now owns it.
+    fn sess(&self) -> &Session;
+
+    /// Provides a uniform interface for re-extracting a reference to an
+    /// `hir_map::Map` from a value that now owns it.
+    fn hir_map(&self) -> Option<hir_map::Map<'hir>>;
+
+    /// Produces the pretty-print annotation object.
+    ///
+    /// (Rust does not yet support upcasting from a trait object to
+    /// an object for one of its supertraits.)
+    fn pp_ann(&self) -> &dyn pprust_hir::PpAnn;
+}
+
+struct NoAnn<'hir> {
+    sess: &'hir Session,
+    tcx: Option<TyCtxt<'hir>>,
+}
+
+impl<'hir> PrinterSupport for NoAnn<'hir> {
+    fn sess(&self) -> &Session {
+        self.sess
+    }
+
+    fn pp_ann(&self) -> &dyn pprust::PpAnn {
+        self
+    }
+}
+
+impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> {
+    fn sess(&self) -> &Session {
+        self.sess
+    }
+
+    fn hir_map(&self) -> Option<hir_map::Map<'hir>> {
+        self.tcx.map(|tcx| tcx.hir())
+    }
+
+    fn pp_ann(&self) -> &dyn pprust_hir::PpAnn {
+        self
+    }
+}
+
+impl<'hir> pprust::PpAnn for NoAnn<'hir> {}
+impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> {
+    fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
+        if let Some(tcx) = self.tcx {
+            pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested)
+        }
+    }
+}
+
+struct IdentifiedAnnotation<'hir> {
+    sess: &'hir Session,
+    tcx: Option<TyCtxt<'hir>>,
+}
+
+impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> {
+    fn sess(&self) -> &Session {
+        self.sess
+    }
+
+    fn pp_ann(&self) -> &dyn pprust::PpAnn {
+        self
+    }
+}
+
+impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> {
+    fn pre(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
+        if let pprust::AnnNode::Expr(_) = node {
+            s.popen();
+        }
+    }
+    fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
+        match node {
+            pprust::AnnNode::Crate(_) | pprust::AnnNode::Ident(_) | pprust::AnnNode::Name(_) => {}
+
+            pprust::AnnNode::Item(item) => {
+                s.s.space();
+                s.synth_comment(item.id.to_string())
+            }
+            pprust::AnnNode::SubItem(id) => {
+                s.s.space();
+                s.synth_comment(id.to_string())
+            }
+            pprust::AnnNode::Block(blk) => {
+                s.s.space();
+                s.synth_comment(format!("block {}", blk.id))
+            }
+            pprust::AnnNode::Expr(expr) => {
+                s.s.space();
+                s.synth_comment(expr.id.to_string());
+                s.pclose()
+            }
+            pprust::AnnNode::Pat(pat) => {
+                s.s.space();
+                s.synth_comment(format!("pat {}", pat.id));
+            }
+        }
+    }
+}
+
+impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> {
+    fn sess(&self) -> &Session {
+        self.sess
+    }
+
+    fn hir_map(&self) -> Option<hir_map::Map<'hir>> {
+        self.tcx.map(|tcx| tcx.hir())
+    }
+
+    fn pp_ann(&self) -> &dyn pprust_hir::PpAnn {
+        self
+    }
+}
+
+impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
+    fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
+        if let Some(ref tcx) = self.tcx {
+            pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested)
+        }
+    }
+    fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
+        if let pprust_hir::AnnNode::Expr(_) = node {
+            s.popen();
+        }
+    }
+    fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
+        match node {
+            pprust_hir::AnnNode::Name(_) => {}
+            pprust_hir::AnnNode::Item(item) => {
+                s.s.space();
+                s.synth_comment(format!("hir_id: {}", item.hir_id()));
+            }
+            pprust_hir::AnnNode::SubItem(id) => {
+                s.s.space();
+                s.synth_comment(id.to_string());
+            }
+            pprust_hir::AnnNode::Block(blk) => {
+                s.s.space();
+                s.synth_comment(format!("block hir_id: {}", blk.hir_id));
+            }
+            pprust_hir::AnnNode::Expr(expr) => {
+                s.s.space();
+                s.synth_comment(format!("expr hir_id: {}", expr.hir_id));
+                s.pclose();
+            }
+            pprust_hir::AnnNode::Pat(pat) => {
+                s.s.space();
+                s.synth_comment(format!("pat hir_id: {}", pat.hir_id));
+            }
+            pprust_hir::AnnNode::Arm(arm) => {
+                s.s.space();
+                s.synth_comment(format!("arm hir_id: {}", arm.hir_id));
+            }
+        }
+    }
+}
+
+struct HygieneAnnotation<'a> {
+    sess: &'a Session,
+}
+
+impl<'a> PrinterSupport for HygieneAnnotation<'a> {
+    fn sess(&self) -> &Session {
+        self.sess
+    }
+
+    fn pp_ann(&self) -> &dyn pprust::PpAnn {
+        self
+    }
+}
+
+impl<'a> pprust::PpAnn for HygieneAnnotation<'a> {
+    fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
+        match node {
+            pprust::AnnNode::Ident(&Ident { name, span }) => {
+                s.s.space();
+                s.synth_comment(format!("{}{:?}", name.as_u32(), span.ctxt()))
+            }
+            pprust::AnnNode::Name(&name) => {
+                s.s.space();
+                s.synth_comment(name.as_u32().to_string())
+            }
+            pprust::AnnNode::Crate(_) => {
+                s.s.hardbreak();
+                let verbose = self.sess.verbose();
+                s.synth_comment(rustc_span::hygiene::debug_hygiene_data(verbose));
+                s.s.hardbreak_if_not_bol();
+            }
+            _ => {}
+        }
+    }
+}
+
+struct TypedAnnotation<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    maybe_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
+}
+
+impl<'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'tcx> {
+    fn sess(&self) -> &Session {
+        self.tcx.sess
+    }
+
+    fn hir_map(&self) -> Option<hir_map::Map<'tcx>> {
+        Some(self.tcx.hir())
+    }
+
+    fn pp_ann(&self) -> &dyn pprust_hir::PpAnn {
+        self
+    }
+}
+
+impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> {
+    fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
+        let old_maybe_typeck_results = self.maybe_typeck_results.get();
+        if let pprust_hir::Nested::Body(id) = nested {
+            self.maybe_typeck_results.set(Some(self.tcx.typeck_body(id)));
+        }
+        let pp_ann = &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>);
+        pprust_hir::PpAnn::nested(pp_ann, state, nested);
+        self.maybe_typeck_results.set(old_maybe_typeck_results);
+    }
+    fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
+        if let pprust_hir::AnnNode::Expr(_) = node {
+            s.popen();
+        }
+    }
+    fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
+        if let pprust_hir::AnnNode::Expr(expr) = node {
+            let typeck_results = self.maybe_typeck_results.get().or_else(|| {
+                self.tcx
+                    .hir()
+                    .maybe_body_owned_by(expr.hir_id.owner.def_id)
+                    .map(|body_id| self.tcx.typeck_body(body_id))
+            });
+
+            if let Some(typeck_results) = typeck_results {
+                s.s.space();
+                s.s.word("as");
+                s.s.space();
+                s.s.word(typeck_results.expr_ty(expr).to_string());
+            }
+
+            s.pclose();
+        }
+    }
+}
+
+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)
+            .expect("get_source_file")
+            .src
+            .as_ref()
+            .expect("src"),
+    );
+    (src, src_name)
+}
+
+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) {
+                sess.emit_fatal(UnprettyDumpFail {
+                    path: p.display().to_string(),
+                    err: e.to_string(),
+                });
+            }
+        }
+    }
+}
+
+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) => {
+            // Silently ignores an identified node.
+            call_with_pp_support(&s, sess, None, move |annotation| {
+                debug!("pretty printing source code {:?}", s);
+                let sess = annotation.sess();
+                let parse = &sess.parse_sess;
+                pprust::print_crate(
+                    sess.source_map(),
+                    krate,
+                    src_name,
+                    src,
+                    annotation.pp_ann(),
+                    false,
+                    parse.edition,
+                    &sess.parse_sess.attr_id_generator,
+                )
+            })
+        }
+        AstTree(PpAstTreeMode::Normal) => {
+            debug!("pretty printing AST tree");
+            format!("{krate:#?}")
+        }
+        _ => unreachable!(),
+    };
+
+    write_or_print(&out, sess);
+}
+
+pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) {
+    if ppm.needs_analysis() {
+        abort_on_err(print_with_analysis(tcx, ppm), tcx.sess);
+        return;
+    }
+
+    let (src, src_name) = get_source(tcx.sess);
+
+    let out = match ppm {
+        Source(s) => {
+            // Silently ignores an identified node.
+            call_with_pp_support(&s, tcx.sess, Some(tcx), move |annotation| {
+                debug!("pretty printing source code {:?}", s);
+                let sess = annotation.sess();
+                let parse = &sess.parse_sess;
+                pprust::print_crate(
+                    sess.source_map(),
+                    &tcx.resolver_for_lowering(()).borrow().1,
+                    src_name,
+                    src,
+                    annotation.pp_ann(),
+                    true,
+                    parse.edition,
+                    &sess.parse_sess.attr_id_generator,
+                )
+            })
+        }
+
+        AstTree(PpAstTreeMode::Expanded) => {
+            debug!("pretty-printing expanded AST");
+            format!("{:#?}", tcx.resolver_for_lowering(()).borrow().1)
+        }
+
+        Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| {
+            debug!("pretty printing HIR {:?}", s);
+            let sess = annotation.sess();
+            let sm = sess.source_map();
+            let attrs = |id| hir_map.attrs(id);
+            pprust_hir::print_crate(
+                sm,
+                hir_map.root_module(),
+                src_name,
+                src,
+                &attrs,
+                annotation.pp_ann(),
+            )
+        }),
+
+        HirTree => {
+            call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, hir_map| {
+                debug!("pretty printing HIR tree");
+                format!("{:#?}", hir_map.krate())
+            })
+        }
+
+        _ => unreachable!(),
+    };
+
+    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) -> Result<(), ErrorGuaranteed> {
+    tcx.analysis(())?;
+    let out = match ppm {
+        Mir => {
+            let mut out = Vec::new();
+            write_mir_pretty(tcx, None, &mut out).unwrap();
+            String::from_utf8(out).unwrap()
+        }
+
+        MirCFG => {
+            let mut out = Vec::new();
+            write_mir_graphviz(tcx, None, &mut out).unwrap();
+            String::from_utf8(out).unwrap()
+        }
+
+        ThirTree => {
+            let mut out = String::new();
+            abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
+            debug!("pretty printing THIR tree");
+            for did in tcx.hir().body_owners() {
+                let _ = writeln!(
+                    out,
+                    "{:?}:\n{}\n",
+                    did,
+                    tcx.thir_tree(ty::WithOptConstParam::unknown(did))
+                );
+            }
+            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, tcx.sess);
+
+    Ok(())
+}
diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs
new file mode 100644 (file)
index 0000000..638b368
--- /dev/null
@@ -0,0 +1,67 @@
+use rustc_macros::Diagnostic;
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_rlink_unable_to_read)]
+pub(crate) struct RlinkUnableToRead {
+    pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_rlink_wrong_file_type)]
+pub(crate) struct RLinkWrongFileType;
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_rlink_empty_version_number)]
+pub(crate) struct RLinkEmptyVersionNumber;
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_rlink_encoding_version_mismatch)]
+pub(crate) struct RLinkEncodingVersionMismatch {
+    pub version_array: String,
+    pub rlink_version: u32,
+}
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_rlink_rustc_version_mismatch)]
+pub(crate) struct RLinkRustcVersionMismatch<'a> {
+    pub rustc_version: String,
+    pub current_version: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_rlink_no_a_file)]
+pub(crate) struct RlinkNotAFile;
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_unpretty_dump_fail)]
+pub(crate) struct UnprettyDumpFail {
+    pub path: String,
+    pub err: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_ice)]
+pub(crate) struct Ice;
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_ice_bug_report)]
+pub(crate) struct IceBugReport<'a> {
+    pub bug_report_url: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_ice_version)]
+pub(crate) struct IceVersion<'a> {
+    pub version: &'a str,
+    pub triple: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_ice_flags)]
+pub(crate) struct IceFlags {
+    pub flags: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_ice_exclude_cargo_defaults)]
+pub(crate) struct IceExcludeCargoDefaults;
index 072b0f2fcceab7e4e357b10fe6f61f85358a66e0..800f3c521778d756f86b6c5e08f00dc76b2f1ada 100644 (file)
 E0520: include_str!("./error_codes/E0520.md"),
 E0521: include_str!("./error_codes/E0521.md"),
 E0522: include_str!("./error_codes/E0522.md"),
+E0523: include_str!("./error_codes/E0523.md"),
 E0524: include_str!("./error_codes/E0524.md"),
 E0525: include_str!("./error_codes/E0525.md"),
 E0527: include_str!("./error_codes/E0527.md"),
 //  E0488, // lifetime of variable does not enclose its declaration
 //  E0489, // type/lifetime parameter not in scope here
 //  E0490, // removed: unreachable
-    E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
 //  E0526, // shuffle indices are not constant
 //  E0540, // multiple rustc_deprecated attributes
 //  E0548, // replaced with a generic attribute input check
index 9108d856c9d7724f557b243130917c9bcca19cc5..209cbb00db562f3daa36e38d79b58e70c938828f 100644 (file)
@@ -1,6 +1,21 @@
 The compiler found multiple library files with the requested crate name.
 
+```compile_fail
+// aux-build:crateresolve-1.rs
+// aux-build:crateresolve-2.rs
+// aux-build:crateresolve-3.rs
+
+extern crate crateresolve;
+//~^ ERROR multiple candidates for `rlib` dependency `crateresolve` found
+
+fn main() {}
+```
+
 This error can occur in several different cases -- for example, when using
 `extern crate` or passing `--extern` options without crate paths. It can also be
 caused by caching issues with the build directory, in which case `cargo clean`
 may help.
+
+In the above example, there are three different library files, all of which
+define the same crate name. Without providing a full path, there is no way for
+the compiler to know which crate it should use.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0523.md b/compiler/rustc_error_codes/src/error_codes/E0523.md
new file mode 100644 (file)
index 0000000..0ddf703
--- /dev/null
@@ -0,0 +1,25 @@
+#### Note: this error code is no longer emitted by the compiler.
+
+The compiler found multiple library files with the requested crate name.
+
+```compile_fail
+// aux-build:crateresolve-1.rs
+// aux-build:crateresolve-2.rs
+// aux-build:crateresolve-3.rs
+
+extern crate crateresolve;
+//~^ ERROR multiple candidates for `rlib` dependency `crateresolve` found
+
+fn main() {}
+```
+
+This error can occur in several different cases -- for example, when using
+`extern crate` or passing `--extern` options without crate paths. It can also be
+caused by caching issues with the build directory, in which case `cargo clean`
+may help.
+
+In the above example, there are three different library files, all of which
+define the same crate name. Without providing a full path, there is no way for
+the compiler to know which crate it should use.
+
+*Note that E0523 has been merged into E0464.*
index 0021638c10268c9ce5fcf68c7ffac5d0793d570c..fe77cf23e8f942fee238c71e3ca30ce2b85e7d66 100644 (file)
@@ -33,7 +33,7 @@ borrowck_var_here_defined = variable defined here
 
 borrowck_var_here_captured = variable captured here
 
-borrowck_closure_inferred_mut =  inferred to be a `FnMut` closure
+borrowck_closure_inferred_mut = inferred to be a `FnMut` closure
 
 borrowck_returned_closure_escaped =
     returns a closure that contains a reference to a captured variable, which then escapes the closure body
index 79ffc82c6c67d096d0f51b3b3030f6263d39ce85..f19b1ff6426177c16eb24dd9093bfa268cb21464 100644 (file)
@@ -1,19 +1,19 @@
-driver_rlink_unable_to_read = failed to read rlink file: `{$err}`
+driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}`
 
-driver_rlink_wrong_file_type = The input does not look like a .rlink file
+driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file
 
-driver_rlink_empty_version_number = The input does not contain version number
+driver_impl_rlink_empty_version_number = The input does not contain version number
 
-driver_rlink_encoding_version_mismatch = .rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}`
+driver_impl_rlink_encoding_version_mismatch = .rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}`
 
-driver_rlink_rustc_version_mismatch = .rlink file was produced by rustc version `{$rustc_version}`, but the current version is `{$current_version}`
+driver_impl_rlink_rustc_version_mismatch = .rlink file was produced by rustc version `{$rustc_version}`, but the current version is `{$current_version}`
 
-driver_rlink_no_a_file = rlink must be a file
+driver_impl_rlink_no_a_file = rlink must be a file
 
-driver_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}`
+driver_impl_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}`
 
-driver_ice = the compiler unexpectedly panicked. this is a bug.
-driver_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
-driver_ice_version = rustc {$version} running on {$triple}
-driver_ice_flags = compiler flags: {$flags}
-driver_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
+driver_impl_ice = the compiler unexpectedly panicked. this is a bug.
+driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
+driver_impl_ice_version = rustc {$version} running on {$triple}
+driver_impl_ice_flags = compiler flags: {$flags}
+driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
index dca678dff7a793253524fe055db88b49934f9dc1..b1e7cc69a809b269ca9a5608656736490b1225bf 100644 (file)
@@ -309,6 +309,7 @@ lint_unused_generator =
     .note = generators are lazy and do nothing unless resumed
 
 lint_unused_def = unused {$pre}`{$def}`{$post} that must be used
+    .suggestion = use `let _ = ...` to ignore the resulting value
 
 lint_path_statement_drop = path statement drops value
     .suggestion = use `drop` to clarify the intent
index 244eb41eb39eba2ba32b4d0556d939293df4fc51..581bb9a766e20640b50b5a279712f27fe4d2b35c 100644 (file)
@@ -128,6 +128,9 @@ parse_missing_in_in_for_loop = missing `in` in `for` loop
     .use_in_not_of = try using `in` here instead
     .add_in = try adding `in` here
 
+parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop
+    .suggestion = try adding an expression to the `for` loop
+
 parse_missing_comma_after_match_arm = expected `,` following `match` arm
     .suggestion = missing a comma here to end this `match` arm
 
@@ -472,6 +475,9 @@ parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`
 parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters
     .note = you cannot use `Self` as a generic parameter because it is reserved for associated items
 
+parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter
+    .label = lifetime parameters cannot have default values
+
 parse_multiple_where_clauses = cannot define duplicate `where` clauses on an item
     .label = previous `where` clause starts here
     .suggestion = consider joining the two `where` clauses into one
index faeaa548619708f5c2c0621f27ac25073b68b715..9768526a2f47d52088fc500e6643b7efad8eca8e 100644 (file)
@@ -1882,9 +1882,8 @@ fn emit_suggestion_default(
                             &mut buffer,
                             &mut row_num,
                             &Vec::new(),
-                            p,
+                            p + line_start,
                             l,
-                            line_start,
                             show_code_change,
                             max_line_num_len,
                             &file_lines,
@@ -1907,9 +1906,8 @@ fn emit_suggestion_default(
                                 &mut buffer,
                                 &mut row_num,
                                 &Vec::new(),
-                                p,
+                                p + line_start,
                                 l,
-                                line_start,
                                 show_code_change,
                                 max_line_num_len,
                                 &file_lines,
@@ -1925,9 +1923,8 @@ fn emit_suggestion_default(
                                 &mut buffer,
                                 &mut row_num,
                                 &Vec::new(),
-                                p,
+                                p + line_start,
                                 l,
-                                line_start,
                                 show_code_change,
                                 max_line_num_len,
                                 &file_lines,
@@ -1941,9 +1938,8 @@ fn emit_suggestion_default(
                     &mut buffer,
                     &mut row_num,
                     highlight_parts,
-                    line_pos,
+                    line_pos + line_start,
                     line,
-                    line_start,
                     show_code_change,
                     max_line_num_len,
                     &file_lines,
@@ -2167,40 +2163,63 @@ fn draw_code_line(
         buffer: &mut StyledBuffer,
         row_num: &mut usize,
         highlight_parts: &Vec<SubstitutionHighlight>,
-        line_pos: usize,
-        line: &str,
-        line_start: usize,
+        line_num: usize,
+        line_to_add: &str,
         show_code_change: DisplaySuggestion,
         max_line_num_len: usize,
         file_lines: &FileLines,
         is_multiline: bool,
     ) {
-        // Print the span column to avoid confusion
-        buffer.puts(*row_num, 0, &self.maybe_anonymized(line_start + line_pos), Style::LineNumber);
         if let DisplaySuggestion::Diff = show_code_change {
-            // Add the line number for both addition and removal to drive the point home.
-            //
-            // N - fn foo<A: T>(bar: A) {
-            // N + fn foo(bar: impl T) {
-            buffer.puts(
-                *row_num - 1,
-                0,
-                &self.maybe_anonymized(line_start + line_pos),
-                Style::LineNumber,
-            );
-            buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
-            buffer.puts(
-                *row_num - 1,
-                max_line_num_len + 3,
-                &normalize_whitespace(
-                    &file_lines.file.get_line(file_lines.lines[line_pos].line_index).unwrap(),
-                ),
-                Style::NoStyle,
-            );
-            buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
+            // We need to print more than one line if the span we need to remove is multiline.
+            // For more info: https://github.com/rust-lang/rust/issues/92741
+            let lines_to_remove = file_lines.lines.iter().take(file_lines.lines.len() - 1);
+            for (index, line_to_remove) in lines_to_remove.enumerate() {
+                buffer.puts(
+                    *row_num - 1,
+                    0,
+                    &self.maybe_anonymized(line_num + index),
+                    Style::LineNumber,
+                );
+                buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
+                let line = normalize_whitespace(
+                    &file_lines.file.get_line(line_to_remove.line_index).unwrap(),
+                );
+                buffer.puts(*row_num - 1, max_line_num_len + 3, &line, Style::NoStyle);
+                *row_num += 1;
+            }
+            // If the last line is exactly equal to the line we need to add, we can skip both of them.
+            // This allows us to avoid output like the following:
+            // 2 - &
+            // 2 + if true { true } else { false }
+            // 3 - if true { true } else { false }
+            // If those lines aren't equal, we print their diff
+            let last_line_index = file_lines.lines[file_lines.lines.len() - 1].line_index;
+            let last_line = &file_lines.file.get_line(last_line_index).unwrap();
+            if last_line != line_to_add {
+                buffer.puts(
+                    *row_num - 1,
+                    0,
+                    &self.maybe_anonymized(line_num + file_lines.lines.len() - 1),
+                    Style::LineNumber,
+                );
+                buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
+                buffer.puts(
+                    *row_num - 1,
+                    max_line_num_len + 3,
+                    &normalize_whitespace(last_line),
+                    Style::NoStyle,
+                );
+                buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
+                buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
+                buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
+            } else {
+                *row_num -= 2;
+            }
         } else if is_multiline {
+            buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
             match &highlight_parts[..] {
-                [SubstitutionHighlight { start: 0, end }] if *end == line.len() => {
+                [SubstitutionHighlight { start: 0, end }] if *end == line_to_add.len() => {
                     buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
                 }
                 [] => {
@@ -2210,17 +2229,17 @@ fn draw_code_line(
                     buffer.puts(*row_num, max_line_num_len + 1, "~ ", Style::Addition);
                 }
             }
+            buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
         } else {
+            buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
             draw_col_separator(buffer, *row_num, max_line_num_len + 1);
+            buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
         }
 
-        // print the suggestion
-        buffer.append(*row_num, &normalize_whitespace(line), Style::NoStyle);
-
         // Colorize addition/replacements with green.
         for &SubstitutionHighlight { start, end } in highlight_parts {
             // Account for tabs when highlighting (#87972).
-            let tabs: usize = line
+            let tabs: usize = line_to_add
                 .chars()
                 .take(start)
                 .map(|ch| match ch {
index 5a48473d5b07c90646808d0daa86112b2a124f21..cf7cff739b340f346ac59d75309c3a13f4fd109c 100644 (file)
@@ -1,11 +1,6 @@
 #![deny(rustc::untranslatable_diagnostic)]
 
-use crate::errors::{
-    ArgumentNotAttributes, AttrNoArguments, AttributeMetaItem, AttributeSingleWord,
-    AttributesWrongForm, CannotBeNameOfMacro, ExpectedCommaInList, HelperAttributeNameInvalid,
-    MacroBodyStability, MacroConstStability, NotAMetaItem, OnlyOneArgument, OnlyOneWord,
-    ResolveRelativePath, TakesNoArguments, TraceMacro,
-};
+use crate::errors;
 use crate::expand::{self, AstFragment, Invocation};
 use crate::module::DirOwnership;
 
@@ -796,13 +791,13 @@ pub fn new(
             .unwrap_or_else(|| (None, helper_attrs));
         let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span);
         if let Some((_, sp)) = const_stability {
-            sess.emit_err(MacroConstStability {
+            sess.emit_err(errors::MacroConstStability {
                 span: sp,
                 head_span: sess.source_map().guess_head_span(span),
             });
         }
         if let Some((_, sp)) = body_stability {
-            sess.emit_err(MacroBodyStability {
+            sess.emit_err(errors::MacroBodyStability {
                 span: sp,
                 head_span: sess.source_map().guess_head_span(span),
             });
@@ -1143,7 +1138,7 @@ pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
     }
     pub fn trace_macros_diag(&mut self) {
         for (span, notes) in self.expansions.iter() {
-            let mut db = self.sess.parse_sess.create_note(TraceMacro { span: *span });
+            let mut db = self.sess.parse_sess.create_note(errors::TraceMacro { span: *span });
             for note in notes {
                 db.note(note);
             }
@@ -1197,7 +1192,7 @@ pub fn resolve_path(
                 .expect("attempting to resolve a file path in an external file"),
             FileName::DocTest(path, _) => path,
             other => {
-                return Err(ResolveRelativePath {
+                return Err(errors::ResolveRelativePath {
                     span,
                     path: parse_sess.source_map().filename_for_diagnostics(&other).to_string(),
                 }
@@ -1279,7 +1274,7 @@ pub fn expr_to_string(
 /// done as rarely as possible).
 pub fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) {
     if !tts.is_empty() {
-        cx.emit_err(TakesNoArguments { span, name });
+        cx.emit_err(errors::TakesNoArguments { span, name });
     }
 }
 
@@ -1307,14 +1302,14 @@ pub fn get_single_str_from_tts(
 ) -> Option<Symbol> {
     let mut p = cx.new_parser_from_tts(tts);
     if p.token == token::Eof {
-        cx.emit_err(OnlyOneArgument { span, name });
+        cx.emit_err(errors::OnlyOneArgument { span, name });
         return None;
     }
     let ret = parse_expr(&mut p)?;
     let _ = p.eat(&token::Comma);
 
     if p.token != token::Eof {
-        cx.emit_err(OnlyOneArgument { span, name });
+        cx.emit_err(errors::OnlyOneArgument { span, name });
     }
     expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s)
 }
@@ -1336,7 +1331,7 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, tts: TokenStream) -> Option<Vec<
             continue;
         }
         if p.token != token::Eof {
-            cx.emit_err(ExpectedCommaInList { span: p.token.span });
+            cx.emit_err(errors::ExpectedCommaInList { span: p.token.span });
             return None;
         }
     }
@@ -1353,51 +1348,58 @@ pub fn parse_macro_name_and_helper_attrs(
     // `#[proc_macro_derive(Foo, attributes(A, ..))]`
     let list = attr.meta_item_list()?;
     if list.len() != 1 && list.len() != 2 {
-        diag.emit_err(AttrNoArguments { span: attr.span });
+        diag.emit_err(errors::AttrNoArguments { span: attr.span });
         return None;
     }
     let Some(trait_attr) = list[0].meta_item() else {
-        diag.emit_err(NotAMetaItem {span: list[0].span()});
+        diag.emit_err(errors::NotAMetaItem {span: list[0].span()});
         return None;
     };
     let trait_ident = match trait_attr.ident() {
         Some(trait_ident) if trait_attr.is_word() => trait_ident,
         _ => {
-            diag.emit_err(OnlyOneWord { span: trait_attr.span });
+            diag.emit_err(errors::OnlyOneWord { span: trait_attr.span });
             return None;
         }
     };
 
     if !trait_ident.name.can_be_raw() {
-        diag.emit_err(CannotBeNameOfMacro { span: trait_attr.span, trait_ident, macro_type });
+        diag.emit_err(errors::CannotBeNameOfMacro {
+            span: trait_attr.span,
+            trait_ident,
+            macro_type,
+        });
     }
 
     let attributes_attr = list.get(1);
     let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
         if !attr.has_name(sym::attributes) {
-            diag.emit_err(ArgumentNotAttributes { span: attr.span() });
+            diag.emit_err(errors::ArgumentNotAttributes { span: attr.span() });
         }
         attr.meta_item_list()
             .unwrap_or_else(|| {
-                diag.emit_err(AttributesWrongForm { span: attr.span() });
+                diag.emit_err(errors::AttributesWrongForm { span: attr.span() });
                 &[]
             })
             .iter()
             .filter_map(|attr| {
                 let Some(attr) = attr.meta_item() else {
-                    diag.emit_err(AttributeMetaItem { span: attr.span() });
+                    diag.emit_err(errors::AttributeMetaItem { span: attr.span() });
                     return None;
                 };
 
                 let ident = match attr.ident() {
                     Some(ident) if attr.is_word() => ident,
                     _ => {
-                        diag.emit_err(AttributeSingleWord { span: attr.span });
+                        diag.emit_err(errors::AttributeSingleWord { span: attr.span });
                         return None;
                     }
                 };
                 if !ident.name.can_be_raw() {
-                    diag.emit_err(HelperAttributeNameInvalid { span: attr.span, name: ident });
+                    diag.emit_err(errors::HelperAttributeNameInvalid {
+                        span: attr.span,
+                        name: ident,
+                    });
                 }
 
                 Some(ident.name)
index 0761d8cdbd8f641da9510c74fb0dc69871624256..c939c8303bf200e4d7a2b7c981356d943ba9c8cf 100644 (file)
@@ -15,9 +15,7 @@ rustc_middle = { path = "../rustc_middle" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
-rustc_graphviz = { path = "../rustc_graphviz" }
 rustc_hir = { path = "../rustc_hir" }
-rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_target = { path = "../rustc_target" }
 rustc_session = { path = "../rustc_session" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
@@ -27,6 +25,5 @@ rustc_index = { path = "../rustc_index" }
 rustc_infer = { path = "../rustc_infer" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_lint = { path = "../rustc_lint" }
-rustc_serialize = { path = "../rustc_serialize" }
 rustc_type_ir = { path = "../rustc_type_ir" }
 rustc_feature = { path = "../rustc_feature" }
index bec9f0ff0772cb8a9862d65f761f07282b4be2cf..3d5f189e233bb5f8f87753898f1bd89ba3f4c8cd 100644 (file)
@@ -2945,12 +2945,12 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                     if r.is_erased() { tcx.lifetimes.re_static } else { r }
                 });
                 let span = ast_ty.span;
-                tcx.sess.emit_err(TypeofReservedKeywordUsed {
-                    span,
-                    ty,
-                    opt_sugg: Some((span, Applicability::MachineApplicable))
-                        .filter(|_| ty.is_suggestable(tcx, false)),
-                });
+                let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false) {
+                    (ty, Some((span, Applicability::MachineApplicable)))
+                } else {
+                    (ty, None)
+                };
+                tcx.sess.emit_err(TypeofReservedKeywordUsed { span, ty, opt_sugg });
 
                 ty
             }
index 6600e4216bd1f4a54304af6e41bc128ff22d4670..8c2423e3ca0d1f78f9c8847a73171c6fe7b1a207 100644 (file)
@@ -176,6 +176,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
                 bounds.iter().map(|(param, constraint, def_id)| {
                     (param.as_str(), constraint.as_str(), *def_id)
                 }),
+                None,
             );
             err.emit();
         }
index cc7235a61c0b822ef6c9ba0cbc71162b2ab949f9..80426c239ac8b8f9ab6506324aa685e10583197c 100644 (file)
@@ -1199,28 +1199,22 @@ fn infer_return_ty_for_fn_sig<'tcx>(
             visitor.visit_ty(ty);
             let mut diag = bad_placeholder(tcx, visitor.0, "return type");
             let ret_ty = fn_sig.output();
-            if ret_ty.is_suggestable(tcx, false) {
+            if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false) {
                 diag.span_suggestion(
                     ty.span,
                     "replace with the correct return type",
                     ret_ty,
                     Applicability::MachineApplicable,
                 );
-            } else if matches!(ret_ty.kind(), ty::FnDef(..)) {
-                let fn_sig = ret_ty.fn_sig(tcx);
-                if fn_sig
-                    .skip_binder()
-                    .inputs_and_output
-                    .iter()
-                    .all(|t| t.is_suggestable(tcx, false))
-                {
-                    diag.span_suggestion(
-                        ty.span,
-                        "replace with the correct return type",
-                        fn_sig,
-                        Applicability::MachineApplicable,
-                    );
-                }
+            } else if matches!(ret_ty.kind(), ty::FnDef(..))
+                && let Some(fn_sig) = ret_ty.fn_sig(tcx).make_suggestable(tcx, false)
+            {
+                diag.span_suggestion(
+                    ty.span,
+                    "replace with the correct return type",
+                    fn_sig,
+                    Applicability::MachineApplicable,
+                );
             } else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, hir_id, def_id) {
                 diag.span_suggestion(
                     ty.span,
@@ -1280,9 +1274,7 @@ fn suggest_impl_trait<'tcx>(
             let trait_name = tcx.item_name(trait_def_id);
             let args_tuple = substs.type_at(1);
             let ty::Tuple(types) = *args_tuple.kind() else { return None; };
-            if !types.is_suggestable(tcx, false) {
-                return None;
-            }
+            let types = types.make_suggestable(tcx, false)?;
             let maybe_ret =
                 if item_ty.is_unit() { String::new() } else { format!(" -> {item_ty}") };
             Some(format!(
@@ -1337,7 +1329,7 @@ fn suggest_impl_trait<'tcx>(
         // FIXME(compiler-errors): We may benefit from resolving regions here.
         if ocx.select_where_possible().is_empty()
             && let item_ty = infcx.resolve_vars_if_possible(item_ty)
-            && item_ty.is_suggestable(tcx, false)
+            && let Some(item_ty) = item_ty.make_suggestable(tcx, false)
             && let Some(sugg) = formatter(tcx, infcx.resolve_vars_if_possible(substs), trait_def_id, assoc_item_def_id, item_ty)
         {
             return Some(sugg);
index e7b0846e10352b1093b1d7efdd2174629513267e..c5522c94874dd3c3421e3a20e6f71f67be3d7780 100644 (file)
@@ -8,7 +8,9 @@
 use rustc_middle::ty::print::with_forced_trimmed_paths;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
+use rustc_middle::ty::{
+    self, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable,
+};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
@@ -845,37 +847,23 @@ fn infer_placeholder_type<'a>(
 ) -> Ty<'a> {
     // Attempts to make the type nameable by turning FnDefs into FnPtrs.
     struct MakeNameable<'tcx> {
-        success: bool,
         tcx: TyCtxt<'tcx>,
     }
 
-    impl<'tcx> MakeNameable<'tcx> {
-        fn new(tcx: TyCtxt<'tcx>) -> Self {
-            MakeNameable { success: true, tcx }
-        }
-    }
-
     impl<'tcx> TypeFolder<'tcx> for MakeNameable<'tcx> {
         fn tcx(&self) -> TyCtxt<'tcx> {
             self.tcx
         }
 
         fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-            if !self.success {
-                return ty;
-            }
-
-            match ty.kind() {
+            let ty = match *ty.kind() {
                 ty::FnDef(def_id, substs) => {
-                    self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id).subst(self.tcx, 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;
-                    ty
-                }
-                _ => ty.super_fold_with(self),
-            }
+                _ => ty,
+            };
+
+            ty.super_fold_with(self)
         }
     }
 
@@ -898,15 +886,11 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                     suggestions.clear();
                 }
 
-                // Suggesting unnameable types won't help.
-                let mut mk_nameable = MakeNameable::new(tcx);
-                let ty = mk_nameable.fold_ty(ty);
-                let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
-                if let Some(sugg_ty) = sugg_ty {
+                if let Some(ty) = ty.make_suggestable(tcx, false) {
                     err.span_suggestion(
                         span,
                         &format!("provide a type for the {item}", item = kind),
-                        format!("{colon} {sugg_ty}"),
+                        format!("{colon} {ty}"),
                         Applicability::MachineApplicable,
                     );
                 } else {
@@ -923,15 +907,12 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             let mut diag = bad_placeholder(tcx, vec![span], kind);
 
             if !ty.references_error() {
-                let mut mk_nameable = MakeNameable::new(tcx);
-                let ty = mk_nameable.fold_ty(ty);
-                let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
-                if let Some(sugg_ty) = sugg_ty {
+                if let Some(ty) = ty.make_suggestable(tcx, false) {
                     diag.span_suggestion(
                         span,
                         "replace with the correct type",
-                        sugg_ty,
-                        Applicability::MaybeIncorrect,
+                        ty,
+                        Applicability::MachineApplicable,
                     );
                 } else {
                     with_forced_trimmed_paths!(diag.span_note(
index 19b8fb96cde37133145ed156b3477c887c8225ee..c4905a934cb4eb7beba493edd756951ea5983a8c 100644 (file)
@@ -60,6 +60,7 @@ pub fn emit_type_mismatch_suggestions(
             || 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_null_ptr_for_literal_zero_given_to_ptr_arg(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, expr.span);
index 237142acca6604a8af1731bd66919209b9ee7a09..e84b3de124c58070388d3b741de2630569a215ff 100644 (file)
@@ -921,6 +921,22 @@ pub(in super::super) fn get_node_fn_decl(
                 kind: hir::ImplItemKind::Fn(ref sig, ..),
                 ..
             }) => Some((&sig.decl, ident, false)),
+            Node::Expr(&hir::Expr {
+                hir_id,
+                kind: hir::ExprKind::Closure(..),
+                ..
+            }) if let Some(Node::Expr(&hir::Expr {
+                hir_id,
+                kind: hir::ExprKind::Call(..),
+                ..
+            })) = self.tcx.hir().find_parent(hir_id) &&
+            let Some(Node::Item(&hir::Item {
+                ident,
+                kind: hir::ItemKind::Fn(ref sig, ..),
+                ..
+            })) = self.tcx.hir().find_parent(hir_id) => {
+                Some((&sig.decl, ident, ident.name != sym::main))
+            },
             _ => None,
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
new file mode 100644 (file)
index 0000000..db1acb5
--- /dev/null
@@ -0,0 +1,829 @@
+use crate::FnCtxt;
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_hir::def_id::DefId;
+use rustc_infer::traits::ObligationCauseCode;
+use rustc_middle::ty::{self, DefIdTree, Ty, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_span::{self, Span};
+use rustc_trait_selection::traits;
+
+use std::ops::ControlFlow;
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub fn adjust_fulfillment_error_for_expr_obligation(
+        &self,
+        error: &mut traits::FulfillmentError<'tcx>,
+    ) -> bool {
+        let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx))
+            = *error.obligation.cause.code().peel_derives() else { return false; };
+        let hir = self.tcx.hir();
+        let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; };
+
+        let Some(unsubstituted_pred) =
+            self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx)
+            else { return false; };
+
+        let generics = self.tcx.generics_of(def_id);
+        let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
+            ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
+            ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
+            _ => ty::List::empty(),
+        };
+
+        let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| {
+            predicate_substs.types().find_map(|ty| {
+                ty.walk().find_map(|arg| {
+                    if let ty::GenericArgKind::Type(ty) = arg.unpack()
+                        && let ty::Param(param_ty) = ty.kind()
+                        && matches(param_ty)
+                    {
+                        Some(arg)
+                    } else {
+                        None
+                    }
+                })
+            })
+        };
+
+        // Prefer generics that are local to the fn item, since these are likely
+        // to be the cause of the unsatisfied predicate.
+        let mut param_to_point_at = find_param_matching(&|param_ty| {
+            self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id
+        });
+        // Fall back to generic that isn't local to the fn item. This will come
+        // from a trait or impl, for example.
+        let mut fallback_param_to_point_at = find_param_matching(&|param_ty| {
+            self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id
+                && param_ty.name != rustc_span::symbol::kw::SelfUpper
+        });
+        // Finally, the `Self` parameter is possibly the reason that the predicate
+        // is unsatisfied. This is less likely to be true for methods, because
+        // method probe means that we already kinda check that the predicates due
+        // to the `Self` type are true.
+        let mut self_param_to_point_at =
+            find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper);
+
+        // Finally, for ambiguity-related errors, we actually want to look
+        // for a parameter that is the source of the inference type left
+        // over in this predicate.
+        if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
+            fallback_param_to_point_at = None;
+            self_param_to_point_at = None;
+            param_to_point_at =
+                self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
+        }
+
+        if self.closure_span_overlaps_error(error, expr.span) {
+            return false;
+        }
+
+        match &expr.kind {
+            hir::ExprKind::Path(qpath) => {
+                if let hir::Node::Expr(hir::Expr {
+                    kind: hir::ExprKind::Call(callee, args),
+                    hir_id: call_hir_id,
+                    span: call_span,
+                    ..
+                }) = hir.get_parent(expr.hir_id)
+                    && callee.hir_id == expr.hir_id
+                {
+                    if self.closure_span_overlaps_error(error, *call_span) {
+                        return false;
+                    }
+
+                    for param in
+                        [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+                        .into_iter()
+                        .flatten()
+                    {
+                        if self.blame_specific_arg_if_possible(
+                                error,
+                                def_id,
+                                param,
+                                *call_hir_id,
+                                callee.span,
+                                None,
+                                args,
+                            )
+                        {
+                            return true;
+                        }
+                    }
+                }
+                // Notably, we only point to params that are local to the
+                // item we're checking, since those are the ones we are able
+                // to look in the final `hir::PathSegment` for. Everything else
+                // would require a deeper search into the `qpath` than I think
+                // is worthwhile.
+                if let Some(param_to_point_at) = param_to_point_at
+                    && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
+                {
+                    return true;
+                }
+            }
+            hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
+                for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+                    .into_iter()
+                    .flatten()
+                {
+                    if self.blame_specific_arg_if_possible(
+                        error,
+                        def_id,
+                        param,
+                        hir_id,
+                        segment.ident.span,
+                        Some(receiver),
+                        args,
+                    ) {
+                        return true;
+                    }
+                }
+                if let Some(param_to_point_at) = param_to_point_at
+                    && self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment)
+                {
+                    return true;
+                }
+            }
+            hir::ExprKind::Struct(qpath, fields, ..) => {
+                if let Res::Def(
+                    hir::def::DefKind::Struct | hir::def::DefKind::Variant,
+                    variant_def_id,
+                ) = self.typeck_results.borrow().qpath_res(qpath, hir_id)
+                {
+                    for param in
+                        [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+                    {
+                        if let Some(param) = param {
+                            let refined_expr = self.point_at_field_if_possible(
+                                def_id,
+                                param,
+                                variant_def_id,
+                                fields,
+                            );
+
+                            match refined_expr {
+                                None => {}
+                                Some((refined_expr, _)) => {
+                                    error.obligation.cause.span = refined_expr
+                                        .span
+                                        .find_ancestor_in_same_ctxt(error.obligation.cause.span)
+                                        .unwrap_or(refined_expr.span);
+                                    return true;
+                                }
+                            }
+                        }
+                    }
+                }
+                if let Some(param_to_point_at) = param_to_point_at
+                    && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
+                {
+                    return true;
+                }
+            }
+            _ => {}
+        }
+
+        false
+    }
+
+    fn point_at_path_if_possible(
+        &self,
+        error: &mut traits::FulfillmentError<'tcx>,
+        def_id: DefId,
+        param: ty::GenericArg<'tcx>,
+        qpath: &hir::QPath<'tcx>,
+    ) -> bool {
+        match qpath {
+            hir::QPath::Resolved(_, path) => {
+                if let Some(segment) = path.segments.last()
+                    && self.point_at_generic_if_possible(error, def_id, param, segment)
+                {
+                    return true;
+                }
+            }
+            hir::QPath::TypeRelative(_, segment) => {
+                if self.point_at_generic_if_possible(error, def_id, param, segment) {
+                    return true;
+                }
+            }
+            _ => {}
+        }
+
+        false
+    }
+
+    fn point_at_generic_if_possible(
+        &self,
+        error: &mut traits::FulfillmentError<'tcx>,
+        def_id: DefId,
+        param_to_point_at: ty::GenericArg<'tcx>,
+        segment: &hir::PathSegment<'tcx>,
+    ) -> bool {
+        let own_substs = self
+            .tcx
+            .generics_of(def_id)
+            .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
+        let Some((index, _)) = own_substs
+            .iter()
+            .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
+            .enumerate()
+            .find(|(_, arg)| **arg == param_to_point_at) else { return false };
+        let Some(arg) = segment
+            .args()
+            .args
+            .iter()
+            .filter(|arg| matches!(arg, hir::GenericArg::Type(_)))
+            .nth(index) else { return false; };
+        error.obligation.cause.span = arg
+            .span()
+            .find_ancestor_in_same_ctxt(error.obligation.cause.span)
+            .unwrap_or(arg.span());
+        true
+    }
+
+    fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>(
+        &self,
+        item_def_id: DefId,
+        t: T,
+    ) -> Option<ty::GenericArg<'tcx>> {
+        struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
+        impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> {
+            type BreakTy = ty::GenericArg<'tcx>;
+            fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
+                if let Some(origin) = self.0.type_var_origin(ty)
+                    && let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
+                        origin.kind
+                    && let generics = self.0.tcx.generics_of(self.1)
+                    && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
+                    && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1)
+                        .get(index as usize)
+                {
+                    ControlFlow::Break(*subst)
+                } else {
+                    ty.super_visit_with(self)
+                }
+            }
+        }
+        t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value()
+    }
+
+    fn closure_span_overlaps_error(
+        &self,
+        error: &traits::FulfillmentError<'tcx>,
+        span: Span,
+    ) -> bool {
+        if let traits::FulfillmentErrorCode::CodeSelectionError(
+            traits::SelectionError::OutputTypeParameterMismatch(_, expected, _),
+        ) = error.code
+            && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind()
+            && span.overlaps(self.tcx.def_span(*def_id))
+        {
+            true
+        } else {
+            false
+        }
+    }
+
+    fn point_at_field_if_possible(
+        &self,
+        def_id: DefId,
+        param_to_point_at: ty::GenericArg<'tcx>,
+        variant_def_id: DefId,
+        expr_fields: &[hir::ExprField<'tcx>],
+    ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
+        let def = self.tcx.adt_def(def_id);
+
+        let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id);
+        let fields_referencing_param: Vec<_> = def
+            .variant_with_id(variant_def_id)
+            .fields
+            .iter()
+            .filter(|field| {
+                let field_ty = field.ty(self.tcx, identity_substs);
+                Self::find_param_in_ty(field_ty.into(), param_to_point_at)
+            })
+            .collect();
+
+        if let [field] = fields_referencing_param.as_slice() {
+            for expr_field in expr_fields {
+                // Look for the ExprField that matches the field, using the
+                // same rules that check_expr_struct uses for macro hygiene.
+                if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
+                {
+                    return Some((expr_field.expr, self.tcx.type_of(field.did)));
+                }
+            }
+        }
+
+        None
+    }
+
+    /// - `blame_specific_*` means that the function will recursively traverse the expression,
+    /// looking for the most-specific-possible span to blame.
+    ///
+    /// - `point_at_*` means that the function will only go "one level", pointing at the specific
+    /// expression mentioned.
+    ///
+    /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
+    /// the provided function call expression, and mark it as responsible for the fullfillment
+    /// error.
+    fn blame_specific_arg_if_possible(
+        &self,
+        error: &mut traits::FulfillmentError<'tcx>,
+        def_id: DefId,
+        param_to_point_at: ty::GenericArg<'tcx>,
+        call_hir_id: hir::HirId,
+        callee_span: Span,
+        receiver: Option<&'tcx hir::Expr<'tcx>>,
+        args: &'tcx [hir::Expr<'tcx>],
+    ) -> bool {
+        let ty = self.tcx.type_of(def_id);
+        if !ty.is_fn() {
+            return false;
+        }
+        let sig = ty.fn_sig(self.tcx).skip_binder();
+        let args_referencing_param: Vec<_> = sig
+            .inputs()
+            .iter()
+            .enumerate()
+            .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at))
+            .collect();
+        // If there's one field that references the given generic, great!
+        if let [(idx, _)] = args_referencing_param.as_slice()
+            && let Some(arg) = receiver
+                .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
+
+            error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
+
+            if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) {
+                // This is more specific than pointing at the entire argument.
+                self.blame_specific_expr_if_possible(error, arg_expr)
+            }
+
+            error.obligation.cause.map_code(|parent_code| {
+                ObligationCauseCode::FunctionArgumentObligation {
+                    arg_hir_id: arg.hir_id,
+                    call_hir_id,
+                    parent_code,
+                }
+            });
+            return true;
+        } else if args_referencing_param.len() > 0 {
+            // If more than one argument applies, then point to the callee span at least...
+            // We have chance to fix this up further in `point_at_generics_if_possible`
+            error.obligation.cause.span = callee_span;
+        }
+
+        false
+    }
+
+    /**
+     * Recursively searches for the most-specific blamable expression.
+     * For example, if you have a chain of constraints like:
+     * - want `Vec<i32>: Copy`
+     * - because `Option<Vec<i32>>: Copy` needs `Vec<i32>: Copy` because `impl <T: Copy> Copy for Option<T>`
+     * - because `(Option<Vec<i32>, bool)` needs `Option<Vec<i32>>: Copy` because `impl <A: Copy, B: Copy> Copy for (A, B)`
+     * then if you pass in `(Some(vec![1, 2, 3]), false)`, this helper `point_at_specific_expr_if_possible`
+     * will find the expression `vec![1, 2, 3]` as the "most blameable" reason for this missing constraint.
+     *
+     * This function only updates the error span.
+     */
+    pub fn blame_specific_expr_if_possible(
+        &self,
+        error: &mut traits::FulfillmentError<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) {
+        // Whether it succeeded or failed, it likely made some amount of progress.
+        // In the very worst case, it's just the same `expr` we originally passed in.
+        let expr = match self.blame_specific_expr_if_possible_for_obligation_cause_code(
+            &error.obligation.cause.code(),
+            expr,
+        ) {
+            Ok(expr) => expr,
+            Err(expr) => expr,
+        };
+
+        // Either way, use this expression to update the error span.
+        // If it doesn't overlap the existing span at all, use the original span.
+        // FIXME: It would possibly be better to do this more continuously, at each level...
+        error.obligation.cause.span = expr
+            .span
+            .find_ancestor_in_same_ctxt(error.obligation.cause.span)
+            .unwrap_or(error.obligation.cause.span);
+    }
+
+    fn blame_specific_expr_if_possible_for_obligation_cause_code(
+        &self,
+        obligation_cause_code: &traits::ObligationCauseCode<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
+        match obligation_cause_code {
+            traits::ObligationCauseCode::ExprBindingObligation(_, _, _, _) => {
+                // This is the "root"; we assume that the `expr` is already pointing here.
+                // Therefore, we return `Ok` so that this `expr` can be refined further.
+                Ok(expr)
+            }
+            traits::ObligationCauseCode::ImplDerivedObligation(impl_derived) => self
+                .blame_specific_expr_if_possible_for_derived_predicate_obligation(
+                    impl_derived,
+                    expr,
+                ),
+            _ => {
+                // We don't recognize this kind of constraint, so we cannot refine the expression
+                // any further.
+                Err(expr)
+            }
+        }
+    }
+
+    /// We want to achieve the error span in the following example:
+    ///
+    /// ```ignore (just for demonstration)
+    /// struct Burrito<Filling> {
+    ///   filling: Filling,
+    /// }
+    /// impl <Filling: Delicious> Delicious for Burrito<Filling> {}
+    /// fn eat_delicious_food<Food: Delicious>(_food: Food) {}
+    ///
+    /// fn will_type_error() {
+    ///   eat_delicious_food(Burrito { filling: Kale });
+    /// } //                                    ^--- The trait bound `Kale: Delicious`
+    ///   //                                         is not satisfied
+    /// ```
+    ///
+    /// Without calling this function, the error span will cover the entire argument expression.
+    ///
+    /// Before we do any of this logic, we recursively call `point_at_specific_expr_if_possible` on the parent
+    /// obligation. Hence we refine the `expr` "outwards-in" and bail at the first kind of expression/impl we don't recognize.
+    ///
+    /// This function returns a `Result<&Expr, &Expr>` - either way, it returns the `Expr` whose span should be
+    /// reported as an error. If it is `Ok`, then it means it refined successfull. If it is `Err`, then it may be
+    /// only a partial success - but it cannot be refined even further.
+    fn blame_specific_expr_if_possible_for_derived_predicate_obligation(
+        &self,
+        obligation: &traits::ImplDerivedObligationCause<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
+        // First, we attempt to refine the `expr` for our span using the parent obligation.
+        // If this cannot be done, then we are already stuck, so we stop early (hence the use
+        // of the `?` try operator here).
+        let expr = self.blame_specific_expr_if_possible_for_obligation_cause_code(
+            &*obligation.derived.parent_code,
+            expr,
+        )?;
+
+        // This is the "trait" (meaning, the predicate "proved" by this `impl`) which provides the `Self` type we care about.
+        // For the purposes of this function, we hope that it is a `struct` type, and that our current `expr` is a literal of
+        // that struct type.
+        let impl_trait_self_ref: Option<ty::TraitRef<'tcx>> =
+            self.tcx.impl_trait_ref(obligation.impl_def_id).map(|impl_def| impl_def.skip_binder());
+
+        let Some(impl_trait_self_ref) = impl_trait_self_ref else {
+            // It is possible that this is absent. In this case, we make no progress.
+            return Err(expr);
+        };
+
+        // We only really care about the `Self` type itself, which we extract from the ref.
+        let impl_self_ty: Ty<'tcx> = impl_trait_self_ref.self_ty();
+
+        let impl_predicates: ty::GenericPredicates<'tcx> =
+            self.tcx.predicates_of(obligation.impl_def_id);
+        let Some(impl_predicate_index) = obligation.impl_def_predicate_index else {
+            // We don't have the index, so we can only guess.
+            return Err(expr);
+        };
+
+        if impl_predicate_index >= impl_predicates.predicates.len() {
+            // This shouldn't happen, but since this is only a diagnostic improvement, avoid breaking things.
+            return Err(expr);
+        }
+        let relevant_broken_predicate: ty::PredicateKind<'tcx> =
+            impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder();
+
+        match relevant_broken_predicate {
+            ty::PredicateKind::Clause(ty::Clause::Trait(broken_trait)) => {
+                // ...
+                self.blame_specific_part_of_expr_corresponding_to_generic_param(
+                    broken_trait.trait_ref.self_ty().into(),
+                    expr,
+                    impl_self_ty.into(),
+                )
+            }
+            _ => Err(expr),
+        }
+    }
+
+    /// Drills into `expr` to arrive at the equivalent location of `find_generic_param` in `in_ty`.
+    /// For example, given
+    /// - expr: `(Some(vec![1, 2, 3]), false)`
+    /// - param: `T`
+    /// - in_ty: `(Option<Vec<T>, bool)`
+    /// we would drill until we arrive at `vec![1, 2, 3]`.
+    ///
+    /// If successful, we return `Ok(refined_expr)`. If unsuccesful, we return `Err(partially_refined_expr`),
+    /// which will go as far as possible. For example, given `(foo(), false)` instead, we would drill to
+    /// `foo()` and then return `Err("foo()")`.
+    ///
+    /// This means that you can (and should) use the `?` try operator to chain multiple calls to this
+    /// function with different types, since you can only continue drilling the second time if you
+    /// succeeded the first time.
+    fn blame_specific_part_of_expr_corresponding_to_generic_param(
+        &self,
+        param: ty::GenericArg<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
+        in_ty: ty::GenericArg<'tcx>,
+    ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
+        if param == in_ty {
+            // The types match exactly, so we have drilled as far as we can.
+            return Ok(expr);
+        }
+
+        let ty::GenericArgKind::Type(in_ty) = in_ty.unpack() else {
+            return Err(expr);
+        };
+
+        if let (hir::ExprKind::Tup(expr_elements), ty::Tuple(in_ty_elements)) =
+            (&expr.kind, in_ty.kind())
+        {
+            if in_ty_elements.len() != expr_elements.len() {
+                return Err(expr);
+            }
+            // Find out which of `in_ty_elements` refer to `param`.
+            // FIXME: It may be better to take the first if there are multiple,
+            // just so that the error points to a smaller expression.
+            let Some((drill_expr, drill_ty)) = Self::is_iterator_singleton(expr_elements.iter().zip( in_ty_elements.iter()).filter(|(_expr_elem, in_ty_elem)| {
+                Self::find_param_in_ty((*in_ty_elem).into(), param)
+            })) else {
+                // The param is not mentioned, or it is mentioned in multiple indexes.
+                return Err(expr);
+            };
+
+            return self.blame_specific_part_of_expr_corresponding_to_generic_param(
+                param,
+                drill_expr,
+                drill_ty.into(),
+            );
+        }
+
+        if let (
+            hir::ExprKind::Struct(expr_struct_path, expr_struct_fields, _expr_struct_rest),
+            ty::Adt(in_ty_adt, in_ty_adt_generic_args),
+        ) = (&expr.kind, in_ty.kind())
+        {
+            // First, confirm that this struct is the same one as in the types, and if so,
+            // find the right variant.
+            let Res::Def(expr_struct_def_kind, expr_struct_def_id) = self.typeck_results.borrow().qpath_res(expr_struct_path, expr.hir_id) else {
+                return Err(expr);
+            };
+
+            let variant_def_id = match expr_struct_def_kind {
+                hir::def::DefKind::Struct => {
+                    if in_ty_adt.did() != expr_struct_def_id {
+                        // FIXME: Deal with type aliases?
+                        return Err(expr);
+                    }
+                    expr_struct_def_id
+                }
+                hir::def::DefKind::Variant => {
+                    // If this is a variant, its parent is the type definition.
+                    if in_ty_adt.did() != self.tcx.parent(expr_struct_def_id) {
+                        // FIXME: Deal with type aliases?
+                        return Err(expr);
+                    }
+                    expr_struct_def_id
+                }
+                _ => {
+                    return Err(expr);
+                }
+            };
+
+            // We need to know which of the generic parameters mentions our target param.
+            // We expect that at least one of them does, since it is expected to be mentioned.
+            let Some((drill_generic_index, generic_argument_type)) =
+                Self::is_iterator_singleton(
+                    in_ty_adt_generic_args.iter().enumerate().filter(
+                        |(_index, in_ty_generic)| {
+                            Self::find_param_in_ty(*in_ty_generic, param)
+                        },
+                    ),
+                ) else {
+                    return Err(expr);
+                };
+
+            let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
+            if drill_generic_index >= struct_generic_parameters.params.len() {
+                return Err(expr);
+            }
+
+            let param_to_point_at_in_struct = self.tcx.mk_param_from_def(
+                struct_generic_parameters.param_at(drill_generic_index, self.tcx),
+            );
+
+            // We make 3 steps:
+            // Suppose we have a type like
+            // ```ignore (just for demonstration)
+            // struct ExampleStruct<T> {
+            //   enabled: bool,
+            //   item: Option<(usize, T, bool)>,
+            // }
+            //
+            // f(ExampleStruct {
+            //   enabled: false,
+            //   item: Some((0, Box::new(String::new()), 1) }, true)),
+            // });
+            // ```
+            // Here, `f` is passed a `ExampleStruct<Box<String>>`, but it wants
+            // for `String: Copy`, which isn't true here.
+            //
+            // (1) First, we drill into `.item` and highlight that expression
+            // (2) Then we use the template type `Option<(usize, T, bool)>` to
+            //     drill into the `T`, arriving at a `Box<String>` expression.
+            // (3) Then we keep going, drilling into this expression using our
+            //     outer contextual information.
+
+            // (1) Find the (unique) field which mentions the type in our constraint:
+            let (field_expr, field_type) = self
+                .point_at_field_if_possible(
+                    in_ty_adt.did(),
+                    param_to_point_at_in_struct,
+                    variant_def_id,
+                    expr_struct_fields,
+                )
+                .ok_or(expr)?;
+
+            // (2) Continue drilling into the struct, ignoring the struct's
+            // generic argument types.
+            let expr = self.blame_specific_part_of_expr_corresponding_to_generic_param(
+                param_to_point_at_in_struct,
+                field_expr,
+                field_type.into(),
+            )?;
+
+            // (3) Continue drilling into the expression, having "passed
+            // through" the struct entirely.
+            return self.blame_specific_part_of_expr_corresponding_to_generic_param(
+                param,
+                expr,
+                generic_argument_type,
+            );
+        }
+
+        if let (
+            hir::ExprKind::Call(expr_callee, expr_args),
+            ty::Adt(in_ty_adt, in_ty_adt_generic_args),
+        ) = (&expr.kind, in_ty.kind())
+        {
+            let hir::ExprKind::Path(expr_callee_path) = &expr_callee.kind else {
+                // FIXME: This case overlaps with another one worth handling,
+                // which should happen above since it applies to non-ADTs:
+                // we can drill down into regular generic functions.
+                return Err(expr);
+            };
+            // This is (possibly) a constructor call, like `Some(...)` or `MyStruct(a, b, c)`.
+
+            let Res::Def(expr_struct_def_kind, expr_ctor_def_id) = self.typeck_results.borrow().qpath_res(expr_callee_path, expr_callee.hir_id) else {
+                return Err(expr);
+            };
+
+            let variant_def_id = match expr_struct_def_kind {
+                hir::def::DefKind::Ctor(hir::def::CtorOf::Struct, hir::def::CtorKind::Fn) => {
+                    if in_ty_adt.did() != self.tcx.parent(expr_ctor_def_id) {
+                        // FIXME: Deal with type aliases?
+                        return Err(expr);
+                    }
+                    self.tcx.parent(expr_ctor_def_id)
+                }
+                hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, hir::def::CtorKind::Fn) => {
+                    // If this is a variant, its parent is the type definition.
+                    if in_ty_adt.did() != self.tcx.parent(expr_ctor_def_id) {
+                        // FIXME: Deal with type aliases?
+                        return Err(expr);
+                    }
+                    expr_ctor_def_id
+                }
+                _ => {
+                    return Err(expr);
+                }
+            };
+
+            // We need to know which of the generic parameters mentions our target param.
+            // We expect that at least one of them does, since it is expected to be mentioned.
+            let Some((drill_generic_index, generic_argument_type)) =
+                Self::is_iterator_singleton(
+                    in_ty_adt_generic_args.iter().enumerate().filter(
+                        |(_index, in_ty_generic)| {
+                            Self::find_param_in_ty(*in_ty_generic, param)
+                        },
+                    ),
+                ) else {
+                    return Err(expr);
+                };
+
+            let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
+            if drill_generic_index >= struct_generic_parameters.params.len() {
+                return Err(expr);
+            }
+
+            let param_to_point_at_in_struct = self.tcx.mk_param_from_def(
+                struct_generic_parameters.param_at(drill_generic_index, self.tcx),
+            );
+
+            // We make 3 steps:
+            // Suppose we have a type like
+            // ```ignore (just for demonstration)
+            // struct ExampleStruct<T> {
+            //   enabled: bool,
+            //   item: Option<(usize, T, bool)>,
+            // }
+            //
+            // f(ExampleStruct {
+            //   enabled: false,
+            //   item: Some((0, Box::new(String::new()), 1) }, true)),
+            // });
+            // ```
+            // Here, `f` is passed a `ExampleStruct<Box<String>>`, but it wants
+            // for `String: Copy`, which isn't true here.
+            //
+            // (1) First, we drill into `.item` and highlight that expression
+            // (2) Then we use the template type `Option<(usize, T, bool)>` to
+            //     drill into the `T`, arriving at a `Box<String>` expression.
+            // (3) Then we keep going, drilling into this expression using our
+            //     outer contextual information.
+
+            // (1) Find the (unique) field index which mentions the type in our constraint:
+            let Some((field_index, field_type)) = Self::is_iterator_singleton(
+                in_ty_adt
+                    .variant_with_id(variant_def_id)
+                    .fields
+                    .iter()
+                    .map(|field| field.ty(self.tcx, *in_ty_adt_generic_args))
+                    .enumerate()
+                    .filter(|(_index, field_type)| Self::find_param_in_ty((*field_type).into(), param))
+            ) else {
+                return Err(expr);
+            };
+
+            if field_index >= expr_args.len() {
+                return Err(expr);
+            }
+
+            // (2) Continue drilling into the struct, ignoring the struct's
+            // generic argument types.
+            let expr = self.blame_specific_part_of_expr_corresponding_to_generic_param(
+                param_to_point_at_in_struct,
+                &expr_args[field_index],
+                field_type.into(),
+            )?;
+
+            // (3) Continue drilling into the expression, having "passed
+            // through" the struct entirely.
+            return self.blame_specific_part_of_expr_corresponding_to_generic_param(
+                param,
+                expr,
+                generic_argument_type,
+            );
+        }
+
+        // At this point, none of the basic patterns matched.
+        // One major possibility which remains is that we have a function call.
+        // In this case, it's often possible to dive deeper into the call to find something to blame,
+        // but this is not always possible.
+
+        Err(expr)
+    }
+
+    // FIXME: This can be made into a private, non-impl function later.
+    /// Traverses the given ty (either a `ty::Ty` or a `ty::GenericArg`) and searches for references
+    /// to the given `param_to_point_at`. Returns `true` if it finds any use of the param.
+    pub fn find_param_in_ty(
+        ty: ty::GenericArg<'tcx>,
+        param_to_point_at: ty::GenericArg<'tcx>,
+    ) -> bool {
+        let mut walk = ty.walk();
+        while let Some(arg) = walk.next() {
+            if arg == param_to_point_at {
+            return true;
+        } else if let ty::GenericArgKind::Type(ty) = arg.unpack()
+            && let ty::Alias(ty::Projection, ..) = ty.kind()
+        {
+            // This logic may seem a bit strange, but typically when
+            // we have a projection type in a function signature, the
+            // argument that's being passed into that signature is
+            // not actually constraining that projection's substs in
+            // a meaningful way. So we skip it, and see improvements
+            // in some UI tests.
+            walk.skip_current_subtree();
+        }
+        }
+        false
+    }
+
+    // FIXME: This can be made into a private, non-impl function later.
+    /// Returns `Some(iterator.next())` if it has exactly one item, and `None` otherwise.
+    pub fn is_iterator_singleton<T>(mut iterator: impl Iterator<Item = T>) -> Option<T> {
+        match (iterator.next(), iterator.next()) {
+            (_, Some(_)) => None,
+            (first, _) => first,
+        }
+    }
+}
index 47ef106e750321470003d3b25103cbcb25b98d9c..2a1265600de8b32738e227b6670768c98af19401 100644 (file)
@@ -26,7 +26,7 @@
 use rustc_infer::infer::TypeTrace;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor};
+use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty};
 use rustc_session::Session;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{self, sym, Span};
@@ -34,7 +34,6 @@
 
 use std::iter;
 use std::mem;
-use std::ops::ControlFlow;
 use std::slice;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -1757,353 +1756,6 @@ pub(super) fn adjust_fulfillment_errors_for_expr_obligation(
         }
     }
 
-    fn adjust_fulfillment_error_for_expr_obligation(
-        &self,
-        error: &mut traits::FulfillmentError<'tcx>,
-    ) -> bool {
-        let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx))
-            = *error.obligation.cause.code().peel_derives() else { return false; };
-        let hir = self.tcx.hir();
-        let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; };
-
-        let Some(unsubstituted_pred) =
-            self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx)
-            else { return false; };
-
-        let generics = self.tcx.generics_of(def_id);
-        let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
-            ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
-            ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
-            _ => ty::List::empty(),
-        };
-
-        let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| {
-            predicate_substs.types().find_map(|ty| {
-                ty.walk().find_map(|arg| {
-                    if let ty::GenericArgKind::Type(ty) = arg.unpack()
-                        && let ty::Param(param_ty) = ty.kind()
-                        && matches(param_ty)
-                    {
-                        Some(arg)
-                    } else {
-                        None
-                    }
-                })
-            })
-        };
-
-        // Prefer generics that are local to the fn item, since these are likely
-        // to be the cause of the unsatisfied predicate.
-        let mut param_to_point_at = find_param_matching(&|param_ty| {
-            self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id
-        });
-        // Fall back to generic that isn't local to the fn item. This will come
-        // from a trait or impl, for example.
-        let mut fallback_param_to_point_at = find_param_matching(&|param_ty| {
-            self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id
-                && param_ty.name != rustc_span::symbol::kw::SelfUpper
-        });
-        // Finally, the `Self` parameter is possibly the reason that the predicate
-        // is unsatisfied. This is less likely to be true for methods, because
-        // method probe means that we already kinda check that the predicates due
-        // to the `Self` type are true.
-        let mut self_param_to_point_at =
-            find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper);
-
-        // Finally, for ambiguity-related errors, we actually want to look
-        // for a parameter that is the source of the inference type left
-        // over in this predicate.
-        if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
-            fallback_param_to_point_at = None;
-            self_param_to_point_at = None;
-            param_to_point_at =
-                self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
-        }
-
-        if self.closure_span_overlaps_error(error, expr.span) {
-            return false;
-        }
-
-        match &expr.kind {
-            hir::ExprKind::Path(qpath) => {
-                if let hir::Node::Expr(hir::Expr {
-                    kind: hir::ExprKind::Call(callee, args),
-                    hir_id: call_hir_id,
-                    span: call_span,
-                    ..
-                }) = hir.get_parent(expr.hir_id)
-                    && callee.hir_id == expr.hir_id
-                {
-                    if self.closure_span_overlaps_error(error, *call_span) {
-                        return false;
-                    }
-
-                    for param in
-                        [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
-                        .into_iter()
-                        .flatten()
-                    {
-                        if self.point_at_arg_if_possible(
-                                error,
-                                def_id,
-                                param,
-                                *call_hir_id,
-                                callee.span,
-                                None,
-                                args,
-                            )
-                        {
-                            return true;
-                        }
-                    }
-                }
-                // Notably, we only point to params that are local to the
-                // item we're checking, since those are the ones we are able
-                // to look in the final `hir::PathSegment` for. Everything else
-                // would require a deeper search into the `qpath` than I think
-                // is worthwhile.
-                if let Some(param_to_point_at) = param_to_point_at
-                    && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
-                {
-                    return true;
-                }
-            }
-            hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
-                for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
-                    .into_iter()
-                    .flatten()
-                {
-                    if self.point_at_arg_if_possible(
-                        error,
-                        def_id,
-                        param,
-                        hir_id,
-                        segment.ident.span,
-                        Some(receiver),
-                        args,
-                    ) {
-                        return true;
-                    }
-                }
-                if let Some(param_to_point_at) = param_to_point_at
-                    && self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment)
-                {
-                    return true;
-                }
-            }
-            hir::ExprKind::Struct(qpath, fields, ..) => {
-                if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) =
-                    self.typeck_results.borrow().qpath_res(qpath, hir_id)
-                {
-                    for param in
-                        [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
-                    {
-                        if let Some(param) = param
-                            && self.point_at_field_if_possible(
-                                error,
-                                def_id,
-                                param,
-                                variant_def_id,
-                                fields,
-                            )
-                        {
-                            return true;
-                        }
-                    }
-                }
-                if let Some(param_to_point_at) = param_to_point_at
-                    && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
-                {
-                    return true;
-                }
-            }
-            _ => {}
-        }
-
-        false
-    }
-
-    fn closure_span_overlaps_error(
-        &self,
-        error: &traits::FulfillmentError<'tcx>,
-        span: Span,
-    ) -> bool {
-        if let traits::FulfillmentErrorCode::CodeSelectionError(
-            traits::SelectionError::OutputTypeParameterMismatch(_, expected, _),
-        ) = error.code
-            && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind()
-            && span.overlaps(self.tcx.def_span(*def_id))
-        {
-            true
-        } else {
-            false
-        }
-    }
-
-    fn point_at_arg_if_possible(
-        &self,
-        error: &mut traits::FulfillmentError<'tcx>,
-        def_id: DefId,
-        param_to_point_at: ty::GenericArg<'tcx>,
-        call_hir_id: hir::HirId,
-        callee_span: Span,
-        receiver: Option<&'tcx hir::Expr<'tcx>>,
-        args: &'tcx [hir::Expr<'tcx>],
-    ) -> bool {
-        let ty = self.tcx.type_of(def_id);
-        if !ty.is_fn() {
-            return false;
-        }
-        let sig = ty.fn_sig(self.tcx).skip_binder();
-        let args_referencing_param: Vec<_> = sig
-            .inputs()
-            .iter()
-            .enumerate()
-            .filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at))
-            .collect();
-        // If there's one field that references the given generic, great!
-        if let [(idx, _)] = args_referencing_param.as_slice()
-            && let Some(arg) = receiver
-                .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
-            error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
-            error.obligation.cause.map_code(|parent_code| {
-                ObligationCauseCode::FunctionArgumentObligation {
-                    arg_hir_id: arg.hir_id,
-                    call_hir_id,
-                    parent_code,
-                }
-            });
-            return true;
-        } else if args_referencing_param.len() > 0 {
-            // If more than one argument applies, then point to the callee span at least...
-            // We have chance to fix this up further in `point_at_generics_if_possible`
-            error.obligation.cause.span = callee_span;
-        }
-
-        false
-    }
-
-    fn point_at_field_if_possible(
-        &self,
-        error: &mut traits::FulfillmentError<'tcx>,
-        def_id: DefId,
-        param_to_point_at: ty::GenericArg<'tcx>,
-        variant_def_id: DefId,
-        expr_fields: &[hir::ExprField<'tcx>],
-    ) -> bool {
-        let def = self.tcx.adt_def(def_id);
-
-        let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id);
-        let fields_referencing_param: Vec<_> = def
-            .variant_with_id(variant_def_id)
-            .fields
-            .iter()
-            .filter(|field| {
-                let field_ty = field.ty(self.tcx, identity_substs);
-                find_param_in_ty(field_ty, param_to_point_at)
-            })
-            .collect();
-
-        if let [field] = fields_referencing_param.as_slice() {
-            for expr_field in expr_fields {
-                // Look for the ExprField that matches the field, using the
-                // same rules that check_expr_struct uses for macro hygiene.
-                if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
-                {
-                    error.obligation.cause.span = expr_field
-                        .expr
-                        .span
-                        .find_ancestor_in_same_ctxt(error.obligation.cause.span)
-                        .unwrap_or(expr_field.span);
-                    return true;
-                }
-            }
-        }
-
-        false
-    }
-
-    fn point_at_path_if_possible(
-        &self,
-        error: &mut traits::FulfillmentError<'tcx>,
-        def_id: DefId,
-        param: ty::GenericArg<'tcx>,
-        qpath: &QPath<'tcx>,
-    ) -> bool {
-        match qpath {
-            hir::QPath::Resolved(_, path) => {
-                if let Some(segment) = path.segments.last()
-                    && self.point_at_generic_if_possible(error, def_id, param, segment)
-                {
-                    return true;
-                }
-            }
-            hir::QPath::TypeRelative(_, segment) => {
-                if self.point_at_generic_if_possible(error, def_id, param, segment) {
-                    return true;
-                }
-            }
-            _ => {}
-        }
-
-        false
-    }
-
-    fn point_at_generic_if_possible(
-        &self,
-        error: &mut traits::FulfillmentError<'tcx>,
-        def_id: DefId,
-        param_to_point_at: ty::GenericArg<'tcx>,
-        segment: &hir::PathSegment<'tcx>,
-    ) -> bool {
-        let own_substs = self
-            .tcx
-            .generics_of(def_id)
-            .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
-        let Some((index, _)) = own_substs
-            .iter()
-            .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
-            .enumerate()
-            .find(|(_, arg)| **arg == param_to_point_at) else { return false };
-        let Some(arg) = segment
-            .args()
-            .args
-            .iter()
-            .filter(|arg| matches!(arg, hir::GenericArg::Type(_)))
-            .nth(index) else { return false; };
-        error.obligation.cause.span = arg
-            .span()
-            .find_ancestor_in_same_ctxt(error.obligation.cause.span)
-            .unwrap_or(arg.span());
-        true
-    }
-
-    fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>(
-        &self,
-        item_def_id: DefId,
-        t: T,
-    ) -> Option<ty::GenericArg<'tcx>> {
-        struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
-        impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> {
-            type BreakTy = ty::GenericArg<'tcx>;
-            fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
-                if let Some(origin) = self.0.type_var_origin(ty)
-                    && let TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
-                        origin.kind
-                    && let generics = self.0.tcx.generics_of(self.1)
-                    && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
-                    && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1)
-                        .get(index as usize)
-                {
-                    ControlFlow::Break(*subst)
-                } else {
-                    ty.super_visit_with(self)
-                }
-            }
-        }
-        t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value()
-    }
-
     fn label_fn_like(
         &self,
         err: &mut Diagnostic,
@@ -2240,23 +1892,3 @@ fn label_fn_like(
         }
     }
 }
-
-fn find_param_in_ty<'tcx>(ty: Ty<'tcx>, param_to_point_at: ty::GenericArg<'tcx>) -> bool {
-    let mut walk = ty.walk();
-    while let Some(arg) = walk.next() {
-        if arg == param_to_point_at {
-            return true;
-        } else if let ty::GenericArgKind::Type(ty) = arg.unpack()
-            && let ty::Alias(ty::Projection, ..) = ty.kind()
-        {
-            // This logic may seem a bit strange, but typically when
-            // we have a projection type in a function signature, the
-            // argument that's being passed into that signature is
-            // not actually constraining that projection's substs in
-            // a meaningful way. So we skip it, and see improvements
-            // in some UI tests.
-            walk.skip_current_subtree();
-        }
-    }
-    false
-}
index 4940015ddd571811d90137ce5dd33a69cd6ba08f..1e14eddd4c86ef511732e116a9dfeafe69b2ba8e 100644 (file)
@@ -1,4 +1,5 @@
 mod _impl;
+mod adjust_fulfillment_errors;
 mod arg_matrix;
 mod checks;
 mod suggestions;
index 3f433a0928c5502f95003812771405aedd76bcc1..05e976534126b0ca92781196c678623cf5c88dd2 100644 (file)
@@ -13,6 +13,7 @@
 use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::traits::{self, StatementAsExpression};
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
     self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty,
     TypeVisitable,
@@ -687,7 +688,7 @@ pub(in super::super) fn suggest_missing_return_type(
                 return true;
             }
             &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
-                if found.is_suggestable(self.tcx, false) {
+                if let Some(found) = found.make_suggestable(self.tcx, false) {
                     err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() });
                     return true;
                 } else if let ty::Closure(_, substs) = found.kind()
@@ -704,10 +705,38 @@ pub(in super::super) fn suggest_missing_return_type(
                 }
             }
             hir::FnRetTy::Return(ty) => {
+                let span = ty.span;
+
+                if let hir::TyKind::OpaqueDef(item_id, ..) = ty.kind
+                && let hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::OpaqueTy(op_ty),
+                    ..
+                }) = self.tcx.hir().get(item_id.hir_id())
+                && let hir::OpaqueTy {
+                    bounds: [bound], ..
+                } = op_ty
+                && let hir::GenericBound::LangItemTrait(
+                    hir::LangItem::Future, _, _, generic_args) = bound
+                && let hir::GenericArgs { bindings: [ty_binding], .. } = generic_args
+                && let hir::TypeBinding { kind, .. } = ty_binding
+                && let hir::TypeBindingKind::Equality { term } = kind
+                && let hir::Term::Ty(term_ty) = term {
+                    // Check if async function's return type was omitted.
+                    // Don't emit suggestions if the found type is `impl Future<...>`.
+                    debug!("suggest_missing_return_type: found = {:?}", found);
+                    if found.is_suggestable(self.tcx, false) {
+                        if term_ty.span.is_empty() {
+                            err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() });
+                            return true;
+                        } else {
+                            err.subdiagnostic(ExpectedReturnTypeLabel::Other { span, expected });
+                        }
+                    }
+                }
+
                 // Only point to return type if the expected type is the return type, as if they
                 // are not, the expectation must have been caused by something else.
                 debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
-                let span = ty.span;
                 let ty = self.astconv().ast_ty_to_ty(ty);
                 debug!("suggest_missing_return_type: return type {:?}", ty);
                 debug!("suggest_missing_return_type: expected type {:?}", ty);
@@ -1244,6 +1273,49 @@ pub(crate) fn suggest_floating_point_literal(
         }
     }
 
+    /// Suggest providing `std::ptr::null()` or `std::ptr::null_mut()` if they
+    /// pass in a literal 0 to an raw pointer.
+    #[instrument(skip(self, err))]
+    pub(crate) fn suggest_null_ptr_for_literal_zero_given_to_ptr_arg(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+        expected_ty: Ty<'tcx>,
+    ) -> bool {
+        // Expected type needs to be a raw pointer.
+        let ty::RawPtr(ty::TypeAndMut { mutbl, .. }) = expected_ty.kind() else {
+            return false;
+        };
+
+        // Provided expression needs to be a literal `0`.
+        let ExprKind::Lit(Spanned {
+            node: rustc_ast::LitKind::Int(0, _),
+            span,
+        }) = expr.kind else {
+            return false;
+        };
+
+        // We need to find a null pointer symbol to suggest
+        let null_sym = match mutbl {
+            hir::Mutability::Not => sym::ptr_null,
+            hir::Mutability::Mut => sym::ptr_null_mut,
+        };
+        let Some(null_did) = self.tcx.get_diagnostic_item(null_sym) else {
+            return false;
+        };
+        let null_path_str = with_no_trimmed_paths!(self.tcx.def_path_str(null_did));
+
+        // We have satisfied all requirements to provide a suggestion. Emit it.
+        err.span_suggestion(
+            span,
+            format!("if you meant to create a null pointer, use `{null_path_str}()`"),
+            null_path_str + "()",
+            Applicability::MachineApplicable,
+        );
+
+        true
+    }
+
     pub(crate) fn suggest_associated_const(
         &self,
         err: &mut Diagnostic,
@@ -1385,6 +1457,7 @@ pub(crate) fn note_type_is_not_clone(
                     generics,
                     diag,
                     vec![(param.name.as_str(), "Clone", Some(clone_trait_did))].into_iter(),
+                    None,
                 );
             } else {
                 self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
index 0b30bf957a3d3dba303edeb2da613d44411c84e6..9ab29a6778fc91eceb2a99bd4ae9f9cbba5683ca 100644 (file)
@@ -1563,6 +1563,7 @@ fn consider_probe(
                                     traits::ImplDerivedObligationCause {
                                         derived,
                                         impl_def_id,
+                                        impl_def_predicate_index: None,
                                         span,
                                     },
                                 ))
index 67769fe4478a24a081c41e42f0f63aee00ab70cd..ba72aefe39c169f7472b3860dca791fe644b5e5d 100644 (file)
@@ -490,9 +490,9 @@ fn check_overloaded_binop(
                                             if let Some(output_def_id) = output_def_id
                                                 && let Some(trait_def_id) = trait_def_id
                                                 && self.tcx.parent(output_def_id) == trait_def_id
-                                                && output_ty.is_suggestable(self.tcx, false)
+                                                && let Some(output_ty) = output_ty.make_suggestable(self.tcx, false)
                                             {
-                                                Some(("Output", *output_ty))
+                                                Some(("Output", output_ty))
                                             } else {
                                                 None
                                             }
index aced787d6711600ee0337b7ee4dd16a3c736973b..02ac83a5e8b25b3f32ecdbfb62d81013c34a71f3 100644 (file)
@@ -15,7 +15,6 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
-rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
index 3e8e7734a5a5de61d34fefba70cf674f0be512d7..7cc9e49b1b62adf66597091e683e21525347ca8f 100644 (file)
@@ -268,14 +268,12 @@ pub fn instantiate_nll_query_response_and_region_obligations<R>(
                 (GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => {
                     // To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
                     if v_o != v_r {
-                        output_query_region_constraints.outlives.push((
-                            ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)),
-                            constraint_category,
-                        ));
-                        output_query_region_constraints.outlives.push((
-                            ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)),
-                            constraint_category,
-                        ));
+                        output_query_region_constraints
+                            .outlives
+                            .push((ty::OutlivesPredicate(v_o.into(), v_r), constraint_category));
+                        output_query_region_constraints
+                            .outlives
+                            .push((ty::OutlivesPredicate(v_r.into(), v_o), constraint_category));
                     }
                 }
 
@@ -318,10 +316,8 @@ pub fn instantiate_nll_query_response_and_region_obligations<R>(
             query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| {
                 let r_c = substitute_value(self.tcx, &result_subst, r_c);
 
-                // Screen out `'a: 'a` cases -- we skip the binder here but
-                // only compare the inner values to one another, so they are still at
-                // consistent binding levels.
-                let ty::OutlivesPredicate(k1, r2) = r_c.0.skip_binder();
+                // Screen out `'a: 'a` cases.
+                let ty::OutlivesPredicate(k1, r2) = r_c.0;
                 if k1 != r2.into() { Some(r_c) } else { None }
             }),
         );
@@ -559,11 +555,11 @@ fn query_outlives_constraints_into_obligations<'a>(
 
     pub fn query_outlives_constraint_to_obligation(
         &self,
-        predicate: QueryOutlivesConstraint<'tcx>,
+        (predicate, _): QueryOutlivesConstraint<'tcx>,
         cause: ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Obligation<'tcx, ty::Predicate<'tcx>> {
-        let ty::OutlivesPredicate(k1, r2) = predicate.0.skip_binder();
+        let ty::OutlivesPredicate(k1, r2) = predicate;
 
         let atom = match k1.unpack() {
             GenericArgKind::Lifetime(r1) => {
@@ -578,7 +574,7 @@ pub fn query_outlives_constraint_to_obligation(
                 span_bug!(cause.span, "unexpected const outlives {:?}", predicate);
             }
         };
-        let predicate = predicate.0.rebind(atom);
+        let predicate = ty::Binder::dummy(atom);
 
         Obligation::new(self.tcx, cause, param_env, predicate)
     }
@@ -643,8 +639,7 @@ pub fn make_query_region_constraints<'tcx>(
     let outlives: Vec<_> = constraints
         .iter()
         .map(|(k, origin)| {
-            // no bound vars in the code above
-            let constraint = ty::Binder::dummy(match *k {
+            let constraint = match *k {
                 // Swap regions because we are going from sub (<=) to outlives
                 // (>=).
                 Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
@@ -658,16 +653,12 @@ pub fn make_query_region_constraints<'tcx>(
                     ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
                 }
                 Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
-            });
+            };
             (constraint, origin.to_constraint_category())
         })
-        .chain(
-            outlives_obligations
-                // no bound vars in the code above
-                .map(|(ty, r, constraint_category)| {
-                    (ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), r)), constraint_category)
-                }),
-        )
+        .chain(outlives_obligations.map(|(ty, r, constraint_category)| {
+            (ty::OutlivesPredicate(ty.into(), r), constraint_category)
+        }))
         .collect();
 
     QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() }
index b5c2d14e8d15b05a6e7dd54eaa894e6db8ac33e7..86f3174b7b2bb25e9c82d410761a445a4a5760f9 100644 (file)
@@ -1922,7 +1922,8 @@ fn escape_literal(s: &str) -> String {
                         (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())
+                                && !code.starts_with("\\u") // forbid all Unicode escapes
+                                && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
                             {
                                 err.span_suggestion(
                                     span,
index 39b3c98f0a5ccadd22b3e0ad79ad8c6c0472eccb..984e8cf6a0eb909f872fb50574b53c586847a349 100644 (file)
@@ -77,49 +77,86 @@ pub fn note_and_explain_type_err(
                     (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);
+                        let p_def_id = tcx
+                            .generics_of(body_owner_def_id)
+                            .type_param(p, tcx)
+                            .def_id;
+                        let p_span = tcx.def_span(p_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
+                        let parent = p_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())
+                            .and_then(|id| {
+                                let local_id = hir.local_def_id_to_hir_id(id);
+                                let generics = tcx.hir().find_parent(local_id)?.generics()?;
+                                Some((id, generics))
+                            });
+                        if let Some((local_id, generics)) = parent
                         {
                             // 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
-                                )
+                            // Here, we try to see if there's an existing
+                            // trait implementation that matches the one that
+                            // we're suggesting to restrict. If so, find the
+                            // "end", whether it be at the end of the trait
+                            // or the end of the generic arguments.
+                            let mut matching_span = None;
+                            let mut matched_end_of_args = false;
+                            for bound in generics.bounds_for_param(local_id) {
+                                let potential_spans = bound
+                                    .bounds
+                                    .iter()
+                                    .find_map(|bound| {
+                                        let bound_trait_path = bound.trait_ref()?.path;
+                                        let def_id = bound_trait_path.res.opt_def_id()?;
+                                        let generic_args = bound_trait_path.segments.iter().last().map(|path| path.args());
+                                        (def_id == trait_ref.def_id).then_some((bound_trait_path.span, generic_args))
+                                    });
+
+                                if let Some((end_of_trait, end_of_args)) = potential_spans {
+                                    let args_span = end_of_args.and_then(|args| args.span());
+                                    matched_end_of_args = args_span.is_some();
+                                    matching_span = args_span
+                                        .or_else(|| Some(end_of_trait))
+                                        .map(|span| span.shrink_to_hi());
+                                    break;
+                                }
+                            }
+
+                            if matched_end_of_args {
+                                // Append suggestion to the end of our args
+                                let path = format!(", {}{} = {}",item_name, item_args, p);
+                                note = !suggest_constraining_type_param(
+                                    tcx,
+                                    generics,
+                                    diag,
+                                    &format!("{}", proj.self_ty()),
+                                    &path,
+                                    None,
+                                    matching_span,
+                                );
                             } else {
-                                format!("{}<{}{} = {}>", path, item_name, item_args, p)
-                            };
-                            note = !suggest_constraining_type_param(
-                                tcx,
-                                generics,
-                                diag,
-                                &format!("{}", proj.self_ty()),
-                                &path,
-                                None,
-                            );
+                                // Suggest adding a bound to an existing trait
+                                // or if the trait doesn't exist, add the trait
+                                // and the suggested bounds.
+                                let path = format!("<{}{} = {}>", item_name, item_args, p);
+                                note = !suggest_constraining_type_param(
+                                    tcx,
+                                    generics,
+                                    diag,
+                                    &format!("{}", proj.self_ty()),
+                                    &path,
+                                    None,
+                                    matching_span,
+                                );
+                            }
                         }
                         if note {
                             diag.note("you might be missing a type parameter or trait bound");
index 83d71edc2abd927a640819ce5a71e28b4b8409a4..2355234637c40790013f90ef4a521190aa2cee7c 100644 (file)
@@ -140,79 +140,21 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         }
     }
 
+    #[inline]
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         if !t.needs_infer() && !t.has_erasable_regions() {
-            return t;
-        }
-
-        let tcx = self.infcx.tcx;
-
-        match *t.kind() {
-            ty::Infer(ty::TyVar(v)) => {
-                let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
-                self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy)
-            }
+            t
+        } else {
+            match *t.kind() {
+                ty::Infer(v) => self.fold_infer_ty(v).unwrap_or(t),
 
-            ty::Infer(ty::IntVar(v)) => self.freshen_ty(
-                self.infcx
-                    .inner
-                    .borrow_mut()
-                    .int_unification_table()
-                    .probe_value(v)
-                    .map(|v| v.to_type(tcx)),
-                ty::IntVar(v),
-                ty::FreshIntTy,
-            ),
+                // This code is hot enough that a non-debug assertion here makes a noticeable
+                // difference on benchmarks like `wg-grammar`.
+                #[cfg(debug_assertions)]
+                ty::Placeholder(..) | ty::Bound(..) => bug!("unexpected type {:?}", t),
 
-            ty::Infer(ty::FloatVar(v)) => self.freshen_ty(
-                self.infcx
-                    .inner
-                    .borrow_mut()
-                    .float_unification_table()
-                    .probe_value(v)
-                    .map(|v| v.to_type(tcx)),
-                ty::FloatVar(v),
-                ty::FreshFloatTy,
-            ),
-
-            ty::Infer(ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct)) => {
-                if ct >= self.ty_freshen_count {
-                    bug!(
-                        "Encountered a freshend type with id {} \
-                          but our counter is only at {}",
-                        ct,
-                        self.ty_freshen_count
-                    );
-                }
-                t
+                _ => t.super_fold_with(self),
             }
-
-            ty::Generator(..)
-            | ty::Bool
-            | ty::Char
-            | ty::Int(..)
-            | ty::Uint(..)
-            | ty::Float(..)
-            | ty::Adt(..)
-            | ty::Str
-            | ty::Error(_)
-            | ty::Array(..)
-            | ty::Slice(..)
-            | ty::RawPtr(..)
-            | ty::Ref(..)
-            | ty::FnDef(..)
-            | ty::FnPtr(_)
-            | ty::Dynamic(..)
-            | ty::Never
-            | ty::Tuple(..)
-            | ty::Alias(..)
-            | ty::Foreign(..)
-            | ty::Param(..)
-            | ty::Closure(..)
-            | ty::GeneratorWitnessMIR(..)
-            | ty::GeneratorWitness(..) => t.super_fold_with(self),
-
-            ty::Placeholder(..) | ty::Bound(..) => bug!("unexpected type {:?}", t),
         }
     }
 
@@ -253,3 +195,54 @@ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         }
     }
 }
+
+impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
+    // This is separate from `fold_ty` to keep that method small and inlinable.
+    #[inline(never)]
+    fn fold_infer_ty(&mut self, v: ty::InferTy) -> Option<Ty<'tcx>> {
+        match v {
+            ty::TyVar(v) => {
+                let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
+                Some(self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy))
+            }
+
+            ty::IntVar(v) => Some(
+                self.freshen_ty(
+                    self.infcx
+                        .inner
+                        .borrow_mut()
+                        .int_unification_table()
+                        .probe_value(v)
+                        .map(|v| v.to_type(self.infcx.tcx)),
+                    ty::IntVar(v),
+                    ty::FreshIntTy,
+                ),
+            ),
+
+            ty::FloatVar(v) => Some(
+                self.freshen_ty(
+                    self.infcx
+                        .inner
+                        .borrow_mut()
+                        .float_unification_table()
+                        .probe_value(v)
+                        .map(|v| v.to_type(self.infcx.tcx)),
+                    ty::FloatVar(v),
+                    ty::FreshFloatTy,
+                ),
+            ),
+
+            ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct) => {
+                if ct >= self.ty_freshen_count {
+                    bug!(
+                        "Encountered a freshend type with id {} \
+                          but our counter is only at {}",
+                        ct,
+                        self.ty_freshen_count
+                    );
+                }
+                None
+            }
+        }
+    }
+}
index f39170bb2916de0802b05016d86ef28b90429659..8e0bcff8d0a89cd794fd77d8902dd7d05fb970b7 100644 (file)
@@ -30,7 +30,7 @@
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
 use rustc_middle::ty::visit::TypeVisitable;
 pub use rustc_middle::ty::IntVarValue;
-use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericParamDefKind, InferConst, InferTy, Ty, TyCtxt};
 use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
@@ -1389,8 +1389,8 @@ pub fn resolve_vars_if_possible<T>(&self, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
-        if !value.needs_infer() {
-            return value; // Avoid duplicated subst-folding.
+        if !value.has_non_region_infer() {
+            return value;
         }
         let mut r = resolve::OpportunisticVarResolver::new(self);
         value.fold_with(&mut r)
@@ -1870,9 +1870,33 @@ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
     /// If `ty` is a type variable of some kind, resolve it one level
     /// (but do not resolve types found in the result). If `typ` is
     /// not a type variable, just return it unmodified.
+    #[inline]
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        match *ty.kind() {
-            ty::Infer(ty::TyVar(v)) => {
+        if let ty::Infer(v) = ty.kind() { self.fold_infer_ty(*v).unwrap_or(ty) } else { ty }
+    }
+
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
+            self.infcx
+                .inner
+                .borrow_mut()
+                .const_unification_table()
+                .probe_value(vid)
+                .val
+                .known()
+                .unwrap_or(ct)
+        } else {
+            ct
+        }
+    }
+}
+
+impl<'a, 'tcx> ShallowResolver<'a, 'tcx> {
+    // This is separate from `fold_ty` to keep that method small and inlinable.
+    #[inline(never)]
+    fn fold_infer_ty(&mut self, v: InferTy) -> Option<Ty<'tcx>> {
+        match v {
+            ty::TyVar(v) => {
                 // Not entirely obvious: if `typ` is a type variable,
                 // it can be resolved to an int/float variable, which
                 // can then be recursively resolved, hence the
@@ -1886,41 +1910,26 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                 // Note: if these two lines are combined into one we get
                 // dynamic borrow errors on `self.inner`.
                 let known = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
-                known.map_or(ty, |t| self.fold_ty(t))
+                known.map(|t| self.fold_ty(t))
             }
 
-            ty::Infer(ty::IntVar(v)) => self
+            ty::IntVar(v) => self
                 .infcx
                 .inner
                 .borrow_mut()
                 .int_unification_table()
                 .probe_value(v)
-                .map_or(ty, |v| v.to_type(self.infcx.tcx)),
+                .map(|v| v.to_type(self.infcx.tcx)),
 
-            ty::Infer(ty::FloatVar(v)) => self
+            ty::FloatVar(v) => self
                 .infcx
                 .inner
                 .borrow_mut()
                 .float_unification_table()
                 .probe_value(v)
-                .map_or(ty, |v| v.to_type(self.infcx.tcx)),
+                .map(|v| v.to_type(self.infcx.tcx)),
 
-            _ => ty,
-        }
-    }
-
-    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
-            self.infcx
-                .inner
-                .borrow_mut()
-                .const_unification_table()
-                .probe_value(vid)
-                .val
-                .known()
-                .unwrap_or(ct)
-        } else {
-            ct
+            ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => None,
         }
     }
 }
index f83219b8ee2a0e0ad1e80f374f6d12dd4574aa5c..a2cfe8d88816cb076d97005521da1f0796e0047e 100644 (file)
@@ -817,12 +817,13 @@ impl<'tcx, D> ConstEquateRelation<'tcx> for TypeRelating<'_, 'tcx, D>
 where
     D: TypeRelatingDelegate<'tcx>,
 {
-    fn const_equate_obligation(&mut self, _a: ty::Const<'tcx>, _b: ty::Const<'tcx>) {
-        // We don't have to worry about the equality of consts during borrow checking
-        // as consts always have a static lifetime.
-        // FIXME(oli-obk): is this really true? We can at least have HKL and with
-        // inline consts we may have further lifetimes that may be unsound to treat as
-        // 'static.
+    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
+        self.delegate.register_obligations(vec![Obligation::new(
+            self.tcx(),
+            ObligationCause::dummy(),
+            self.param_env(),
+            ty::Binder::dummy(ty::PredicateKind::ConstEquate(a, b)),
+        )]);
     }
 }
 
index 65b90aa3d79d3e285365339e8ec6812c000e09b6..a39a40cf9abe242f22408b62c077e2d7ef32160e 100644 (file)
 /// useful for printing messages etc but also required at various
 /// points for correctness.
 pub struct OpportunisticVarResolver<'a, 'tcx> {
-    infcx: &'a InferCtxt<'tcx>,
+    // The shallow resolver is used to resolve inference variables at every
+    // level of the type.
+    shallow_resolver: crate::infer::ShallowResolver<'a, 'tcx>,
 }
 
 impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
     #[inline]
     pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
-        OpportunisticVarResolver { infcx }
+        OpportunisticVarResolver { shallow_resolver: crate::infer::ShallowResolver { infcx } }
     }
 }
 
 impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
+        TypeFolder::tcx(&self.shallow_resolver)
     }
 
+    #[inline]
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         if !t.has_non_region_infer() {
             t // micro-optimize -- if there is nothing in this type that this fold affects...
         } else {
-            let t = self.infcx.shallow_resolve(t);
+            let t = self.shallow_resolver.fold_ty(t);
             t.super_fold_with(self)
         }
     }
@@ -44,7 +47,7 @@ fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> {
         if !ct.has_non_region_infer() {
             ct // micro-optimize -- if there is nothing in this const that this fold affects...
         } else {
-            let ct = self.infcx.shallow_resolve(ct);
+            let ct = self.shallow_resolver.fold_const(ct);
             ct.super_fold_with(self)
         }
     }
index cd5bde2a791309c6c0f6d5aa6d73a55e412e0e36..18a966449aa72f2e9432ab3c833d8bdc1ba22bae 100644 (file)
@@ -145,30 +145,32 @@ 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, 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,
-                        cause,
-                    )
-                });
+                let obligations =
+                    predicates.predicates.iter().enumerate().map(|(index, &(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(),
+                                        impl_def_predicate_index: Some(index),
+                                        span,
+                                    },
+                                ))
+                            },
+                        );
+                        predicate_obligation(
+                            pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
+                            obligation.param_env,
+                            cause,
+                        )
+                    });
                 debug!(?data, ?obligations, "super_predicates");
 
                 // Only keep those bounds that we haven't already seen.
index 1199ff287c4302a09ee879e103084ad78e2fd200..955ab3c4680abded5dbdf0c1782c0a9d73a6749a 100644 (file)
@@ -20,7 +20,6 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_parse = { path = "../rustc_parse" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
-rustc_serialize = { path = "../rustc_serialize" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_ast_lowering = { path = "../rustc_ast_lowering" }
 rustc_ast_passes = { path = "../rustc_ast_passes" }
index 60b60edd2c8119a9a2cfb1d2377356a8e3fa0275..2a373ebc1324da0112c47002f85b2b1e86e62b5f 100644 (file)
@@ -1,9 +1,4 @@
-use crate::errors::{
-    CantEmitMIR, EmojiIdentifier, ErrorWritingDependencies, FerrisIdentifier,
-    GeneratedFileConflictsWithDirectory, InputFileWouldBeOverWritten, MixedBinCrate,
-    MixedProcMacroCrate, OutDirError, ProcMacroCratePanicAbort, ProcMacroDocWithoutArg,
-    TempsDirError,
-};
+use crate::errors;
 use crate::interface::{Compiler, Result};
 use crate::proc_macro_decls;
 use crate::util;
@@ -374,15 +369,15 @@ pub fn configure_and_expand(
 
     if crate_types.len() > 1 {
         if is_executable_crate {
-            sess.emit_err(MixedBinCrate);
+            sess.emit_err(errors::MixedBinCrate);
         }
         if is_proc_macro_crate {
-            sess.emit_err(MixedProcMacroCrate);
+            sess.emit_err(errors::MixedProcMacroCrate);
         }
     }
 
     if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
-        sess.emit_warning(ProcMacroCratePanicAbort);
+        sess.emit_warning(errors::ProcMacroCratePanicAbort);
     }
 
     // For backwards compatibility, we don't try to run proc macro injection
@@ -392,7 +387,7 @@ pub fn configure_and_expand(
     // However, we do emit a warning, to let such users know that they should
     // start passing '--crate-type proc-macro'
     if has_proc_macro_decls && sess.opts.actually_rustdoc && !is_proc_macro_crate {
-        sess.emit_warning(ProcMacroDocWithoutArg);
+        sess.emit_warning(errors::ProcMacroDocWithoutArg);
     } else {
         krate = sess.time("maybe_create_a_macro_crate", || {
             let is_test_crate = sess.opts.test;
@@ -441,9 +436,9 @@ pub fn configure_and_expand(
             spans.sort();
             if ident == sym::ferris {
                 let first_span = spans[0];
-                sess.emit_err(FerrisIdentifier { spans, first_span });
+                sess.emit_err(errors::FerrisIdentifier { spans, first_span });
             } else {
-                sess.emit_err(EmojiIdentifier { spans, ident });
+                sess.emit_err(errors::EmojiIdentifier { spans, ident });
             }
         }
     });
@@ -655,7 +650,7 @@ fn write_out_deps(
             }
         }
         Err(error) => {
-            sess.emit_fatal(ErrorWritingDependencies { path: &deps_filename, error });
+            sess.emit_fatal(errors::ErrorWritingDependencies { path: &deps_filename, error });
         }
     }
 }
@@ -676,17 +671,20 @@ fn output_filenames(tcx: TyCtxt<'_>, (): ()) -> Arc<OutputFilenames> {
     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) {
-                sess.emit_fatal(InputFileWouldBeOverWritten { path: input_path });
+                sess.emit_fatal(errors::InputFileWouldBeOverWritten { path: input_path });
             }
             if let Some(ref dir_path) = output_conflicts_with_dir(&output_paths) {
-                sess.emit_fatal(GeneratedFileConflictsWithDirectory { input_path, dir_path });
+                sess.emit_fatal(errors::GeneratedFileConflictsWithDirectory {
+                    input_path,
+                    dir_path,
+                });
             }
         }
     }
 
     if let Some(ref dir) = sess.io.temps_dir {
         if fs::create_dir_all(dir).is_err() {
-            sess.emit_fatal(TempsDirError);
+            sess.emit_fatal(errors::TempsDirError);
         }
     }
 
@@ -698,7 +696,7 @@ fn output_filenames(tcx: TyCtxt<'_>, (): ()) -> Arc<OutputFilenames> {
     if !only_dep_info {
         if let Some(ref dir) = sess.io.output_dir {
             if fs::create_dir_all(dir).is_err() {
-                sess.emit_fatal(OutDirError);
+                sess.emit_fatal(errors::OutDirError);
             }
         }
     }
@@ -977,7 +975,7 @@ pub fn start_codegen<'tcx>(
 
     if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
         if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx) {
-            tcx.sess.emit_err(CantEmitMIR { error });
+            tcx.sess.emit_err(errors::CantEmitMIR { error });
             tcx.sess.abort_if_errors();
         }
     }
index 0c1019545f382f8a5ce425a871a5aa1cc225f149..2e447b900e1174b79ed142bb3c1cbf0d664e34ba 100644 (file)
@@ -1402,6 +1402,21 @@ pub struct UnusedDef<'a, 'b> {
     pub cx: &'a LateContext<'b>,
     pub def_id: DefId,
     pub note: Option<Symbol>,
+    pub suggestion: Option<UnusedDefSuggestion>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum UnusedDefSuggestion {
+    #[suggestion(
+        suggestion,
+        style = "verbose",
+        code = "let _ = ",
+        applicability = "machine-applicable"
+    )]
+    Default {
+        #[primary_span]
+        span: Span,
+    },
 }
 
 // Needed because of def_path_str
@@ -1417,6 +1432,9 @@ fn decorate_lint<'b>(
         if let Some(note) = self.note {
             diag.note(note.as_str());
         }
+        if let Some(sugg) = self.suggestion {
+            diag.subdiagnostic(sugg);
+        }
         diag
     }
 
index d829ca43328fe651422bf31ad61ef2e955bbfe9c..88ea293444c1758e5e28a5e420323116e600d2f7 100644 (file)
@@ -1,7 +1,7 @@
 use crate::lints::{
     PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag,
-    UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDelim, UnusedDelimSuggestion,
-    UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedResult,
+    UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDefSuggestion, UnusedDelim,
+    UnusedDelimSuggestion, UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedResult,
 };
 use crate::Lint;
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
@@ -418,6 +418,19 @@ fn emit_must_use_untranslated(
                     );
                 }
                 MustUsePath::Def(span, def_id, reason) => {
+                    let suggestion = if matches!(
+                        cx.tcx.get_diagnostic_name(*def_id),
+                        Some(sym::add)
+                            | Some(sym::sub)
+                            | Some(sym::mul)
+                            | Some(sym::div)
+                            | Some(sym::rem)
+                            | Some(sym::neg),
+                    ) {
+                        Some(UnusedDefSuggestion::Default { span: span.shrink_to_lo() })
+                    } else {
+                        None
+                    };
                     cx.emit_spanned_lint(
                         UNUSED_MUST_USE,
                         *span,
@@ -427,6 +440,7 @@ fn emit_must_use_untranslated(
                             cx,
                             def_id: *def_id,
                             note: *reason,
+                            suggestion,
                         },
                     );
                 }
@@ -663,6 +677,10 @@ fn emit_unused_delims(
         keep_space: (bool, bool),
     ) {
         let primary_span = if let Some((lo, hi)) = spans {
+            if hi.is_empty() {
+                // do not point at delims that do not exist
+                return;
+            }
             MultiSpan::from(vec![lo, hi])
         } else {
             MultiSpan::from(value_span)
index 727cfc4416ee94889cef6eb11cc01f98e120ab45..9146a3739b2b1b76dfe30a8dd68ec355debede20 100644 (file)
@@ -4,7 +4,6 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
 #include "llvm/Analysis/Lint.h"
 #include "llvm/Analysis/Passes.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/IRPrintingPasses.h"
 #include "llvm/Linker/Linker.h"
 
+#if LLVM_VERSION_GE(16, 0)
+#include "llvm/TargetParser/Triple.h"
+#else
+#include "llvm/ADT/Triple.h"
+#endif
+
 extern "C" void LLVMRustSetLastError(const char *);
 
 enum class LLVMRustResult { Success, Failure };
index f728bff0e3b91a3a1665ae58eab72654474ed1c9..15a4273fc5918e682a97dcb78e53439737b091f4 100644 (file)
@@ -21,6 +21,9 @@
 #include "llvm/Passes/StandardInstrumentations.h"
 #include "llvm/Support/CBindingWrapping.h"
 #include "llvm/Support/FileSystem.h"
+#if LLVM_VERSION_GE(17, 0)
+#include "llvm/Support/VirtualFileSystem.h"
+#endif
 #include "llvm/Support/Host.h"
 #if LLVM_VERSION_LT(14, 0)
 #include "llvm/Support/TargetRegistry.h"
@@ -651,21 +654,40 @@ LLVMRustOptimize(
   Optional<PGOOptions> PGOOpt;
 #else
   std::optional<PGOOptions> PGOOpt;
+#endif
+#if LLVM_VERSION_GE(17, 0)
+  auto FS = vfs::getRealFileSystem();
 #endif
   if (PGOGenPath) {
     assert(!PGOUsePath && !PGOSampleUsePath);
-    PGOOpt = PGOOptions(PGOGenPath, "", "", PGOOptions::IRInstr,
-                        PGOOptions::NoCSAction, DebugInfoForProfiling);
+    PGOOpt = PGOOptions(PGOGenPath, "", "",
+#if LLVM_VERSION_GE(17, 0)
+                        FS,
+#endif
+                        PGOOptions::IRInstr, PGOOptions::NoCSAction,
+                        DebugInfoForProfiling);
   } else if (PGOUsePath) {
     assert(!PGOSampleUsePath);
-    PGOOpt = PGOOptions(PGOUsePath, "", "", PGOOptions::IRUse,
-                        PGOOptions::NoCSAction, DebugInfoForProfiling);
+    PGOOpt = PGOOptions(PGOUsePath, "", "",
+#if LLVM_VERSION_GE(17, 0)
+                        FS,
+#endif
+                        PGOOptions::IRUse, PGOOptions::NoCSAction,
+                        DebugInfoForProfiling);
   } else if (PGOSampleUsePath) {
-    PGOOpt = PGOOptions(PGOSampleUsePath, "", "", PGOOptions::SampleUse,
-                        PGOOptions::NoCSAction, DebugInfoForProfiling);
+    PGOOpt = PGOOptions(PGOSampleUsePath, "", "",
+#if LLVM_VERSION_GE(17, 0)
+                        FS,
+#endif
+                        PGOOptions::SampleUse, PGOOptions::NoCSAction,
+                        DebugInfoForProfiling);
   } else if (DebugInfoForProfiling) {
-    PGOOpt = PGOOptions("", "", "", PGOOptions::NoAction,
-                        PGOOptions::NoCSAction, DebugInfoForProfiling);
+    PGOOpt = PGOOptions("", "", "",
+#if LLVM_VERSION_GE(17, 0)
+                        FS,
+#endif
+                        PGOOptions::NoAction, PGOOptions::NoCSAction,
+                        DebugInfoForProfiling);
   }
 
   PassBuilder PB(TM, PTO, PGOOpt, &PIC);
index 653f2b39d3e74f646e22b01133ff4afe25f29bf4..bf8b8aa2ce49704e13d47567f016d7ad2535e97b 100644 (file)
@@ -1,10 +1,6 @@
 //! Validates all used crates and extern libraries and loads their metadata
 
-use crate::errors::{
-    ConflictingAllocErrorHandler, ConflictingGlobalAlloc, CrateNotPanicRuntime,
-    GlobalAllocRequired, NoMultipleAllocErrorHandler, NoMultipleGlobalAlloc, NoPanicStrategy,
-    NoTransitiveNeedsDep, NotProfilerRuntime, ProfilerBuiltinsNeedsCore,
-};
+use crate::errors;
 use crate::locator::{CrateError, CrateLocator, CratePaths};
 use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
 
@@ -33,6 +29,7 @@
 use proc_macro::bridge::client::ProcMacro;
 use std::ops::Fn;
 use std::path::Path;
+use std::time::Duration;
 use std::{cmp, env};
 
 #[derive(Clone)]
@@ -359,7 +356,12 @@ fn verify_no_symbol_conflicts(&self, root: &CrateRoot) -> Result<(), CrateError>
         for (_, other) in self.cstore.iter_crate_data() {
             // Same stable crate id but different SVH
             if other.stable_crate_id() == root.stable_crate_id() && other.hash() != root.hash() {
-                return Err(CrateError::SymbolConflictsOthers(root.name()));
+                bug!(
+                    "Previously returned E0523 here. \
+                     See https://github.com/rust-lang/rust/pull/100599 for additional discussion.\
+                     root.name() = {}.",
+                    root.name()
+                );
             }
         }
 
@@ -689,8 +691,7 @@ fn dlsym_proc_macros(
     ) -> Result<&'static [ProcMacro], CrateError> {
         // Make sure the path contains a / or the linker will search for it.
         let path = env::current_dir().unwrap().join(path);
-        let lib = unsafe { libloading::Library::new(path) }
-            .map_err(|err| CrateError::DlOpen(err.to_string()))?;
+        let lib = load_dylib(&path, 5).map_err(|err| CrateError::DlOpen(err))?;
 
         let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
         let sym = unsafe { lib.get::<*const &[ProcMacro]>(sym_name.as_bytes()) }
@@ -768,10 +769,11 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
         // Sanity check the loaded crate to ensure it is indeed a panic runtime
         // and the panic strategy is indeed what we thought it was.
         if !data.is_panic_runtime() {
-            self.sess.emit_err(CrateNotPanicRuntime { crate_name: name });
+            self.sess.emit_err(errors::CrateNotPanicRuntime { crate_name: name });
         }
         if data.required_panic_strategy() != Some(desired_strategy) {
-            self.sess.emit_err(NoPanicStrategy { crate_name: name, strategy: desired_strategy });
+            self.sess
+                .emit_err(errors::NoPanicStrategy { crate_name: name, strategy: desired_strategy });
         }
 
         self.cstore.injected_panic_runtime = Some(cnum);
@@ -791,7 +793,7 @@ fn inject_profiler_runtime(&mut self, krate: &ast::Crate) {
 
         let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
         if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) {
-            self.sess.emit_err(ProfilerBuiltinsNeedsCore);
+            self.sess.emit_err(errors::ProfilerBuiltinsNeedsCore);
         }
 
         let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; };
@@ -799,21 +801,22 @@ fn inject_profiler_runtime(&mut self, krate: &ast::Crate) {
 
         // Sanity check the loaded crate to ensure it is indeed a profiler runtime
         if !data.is_profiler_runtime() {
-            self.sess.emit_err(NotProfilerRuntime { crate_name: name });
+            self.sess.emit_err(errors::NotProfilerRuntime { crate_name: name });
         }
     }
 
     fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
         self.cstore.has_global_allocator = match &*global_allocator_spans(&self.sess, krate) {
             [span1, span2, ..] => {
-                self.sess.emit_err(NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
+                self.sess.emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
                 true
             }
             spans => !spans.is_empty(),
         };
         self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(&self.sess, krate) {
             [span1, span2, ..] => {
-                self.sess.emit_err(NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
+                self.sess
+                    .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
                 true
             }
             spans => !spans.is_empty(),
@@ -849,7 +852,7 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
             if data.has_global_allocator() {
                 match global_allocator {
                     Some(other_crate) => {
-                        self.sess.emit_err(ConflictingGlobalAlloc {
+                        self.sess.emit_err(errors::ConflictingGlobalAlloc {
                             crate_name: data.name(),
                             other_crate_name: other_crate,
                         });
@@ -864,7 +867,7 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
             if data.has_alloc_error_handler() {
                 match alloc_error_handler {
                     Some(other_crate) => {
-                        self.sess.emit_err(ConflictingAllocErrorHandler {
+                        self.sess.emit_err(errors::ConflictingAllocErrorHandler {
                             crate_name: data.name(),
                             other_crate_name: other_crate,
                         });
@@ -884,7 +887,7 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
             if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator)
                 && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
             {
-                self.sess.emit_err(GlobalAllocRequired);
+                self.sess.emit_err(errors::GlobalAllocRequired);
             }
             self.cstore.allocator_kind = Some(AllocatorKind::Default);
         }
@@ -917,7 +920,7 @@ fn inject_dependency_if(
         for dep in self.cstore.crate_dependencies_in_reverse_postorder(krate) {
             let data = self.cstore.get_crate_data(dep);
             if needs_dep(&data) {
-                self.sess.emit_err(NoTransitiveNeedsDep {
+                self.sess.emit_err(errors::NoTransitiveNeedsDep {
                     crate_name: self.cstore.get_crate_data(krate).name(),
                     needs_crate_name: what,
                     deps_crate_name: data.name(),
@@ -1093,3 +1096,41 @@ fn visit_item(&mut self, item: &'ast ast::Item) {
     visit::walk_crate(&mut f, krate);
     f.spans
 }
+
+// On Windows the compiler would sometimes intermittently fail to open the
+// proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the
+// system still holds a lock on the file, so we retry a few times before calling it
+// an error.
+fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, String> {
+    assert!(max_attempts > 0);
+
+    let mut last_error = None;
+
+    for attempt in 0..max_attempts {
+        match unsafe { libloading::Library::new(&path) } {
+            Ok(lib) => {
+                if attempt > 0 {
+                    debug!(
+                        "Loaded proc-macro `{}` after {} attempts.",
+                        path.display(),
+                        attempt + 1
+                    );
+                }
+                return Ok(lib);
+            }
+            Err(err) => {
+                // Only try to recover from this specific error.
+                if !matches!(err, libloading::Error::LoadLibraryExW { .. }) {
+                    return Err(err.to_string());
+                }
+
+                last_error = Some(err);
+                std::thread::sleep(Duration::from_millis(100));
+                debug!("Failed to load proc-macro `{}`. Retrying.", path.display());
+            }
+        }
+    }
+
+    debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts);
+    Err(format!("{} (retried {} times)", last_error.unwrap(), max_attempts))
+}
index 02c03114eb67f637cf5b1236e0d25d1310239019..c32686779facb5be9c91f306815ceba751897316 100644 (file)
@@ -511,14 +511,6 @@ pub struct SymbolConflictsCurrent {
     pub crate_name: Symbol,
 }
 
-#[derive(Diagnostic)]
-#[diag(metadata_symbol_conflicts_others, code = "E0523")]
-pub struct SymbolConflictsOthers {
-    #[primary_span]
-    pub span: Span,
-    pub crate_name: Symbol,
-}
-
 #[derive(Diagnostic)]
 #[diag(metadata_stable_crate_id_collision)]
 pub struct StableCrateIdCollision {
index 0f5f74007c1060536912477a6b5815635a37a7d1..755a24253504ec844eb3be0225a8772db6e0bdc1 100644 (file)
 //! metadata::locator or metadata::creader for all the juicy details!
 
 use crate::creader::Library;
-use crate::errors::{
-    CannotFindCrate, CrateLocationUnknownType, DlError, ExternLocationNotExist,
-    ExternLocationNotFile, FoundStaticlib, IncompatibleRustc, InvalidMetadataFiles,
-    LibFilenameForm, MultipleCandidates, NewerCrateVersion, NoCrateWithTriple, NoDylibPlugin,
-    NonAsciiName, StableCrateIdCollision, SymbolConflictsCurrent, SymbolConflictsOthers,
-};
+use crate::errors;
 use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -950,7 +945,6 @@ pub(crate) enum CrateError {
     ExternLocationNotFile(Symbol, PathBuf),
     MultipleCandidates(Symbol, CrateFlavor, Vec<PathBuf>),
     SymbolConflictsCurrent(Symbol),
-    SymbolConflictsOthers(Symbol),
     StableCrateIdCollision(Symbol, Symbol),
     DlOpen(String),
     DlSym(String),
@@ -980,28 +974,25 @@ impl CrateError {
     pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
         match self {
             CrateError::NonAsciiName(crate_name) => {
-                sess.emit_err(NonAsciiName { span, crate_name });
+                sess.emit_err(errors::NonAsciiName { span, crate_name });
             }
             CrateError::ExternLocationNotExist(crate_name, loc) => {
-                sess.emit_err(ExternLocationNotExist { span, crate_name, location: &loc });
+                sess.emit_err(errors::ExternLocationNotExist { span, crate_name, location: &loc });
             }
             CrateError::ExternLocationNotFile(crate_name, loc) => {
-                sess.emit_err(ExternLocationNotFile { span, crate_name, location: &loc });
+                sess.emit_err(errors::ExternLocationNotFile { span, crate_name, location: &loc });
             }
             CrateError::MultipleCandidates(crate_name, flavor, candidates) => {
-                sess.emit_err(MultipleCandidates { span, crate_name, flavor, candidates });
+                sess.emit_err(errors::MultipleCandidates { span, crate_name, flavor, candidates });
             }
             CrateError::SymbolConflictsCurrent(root_name) => {
-                sess.emit_err(SymbolConflictsCurrent { span, crate_name: root_name });
-            }
-            CrateError::SymbolConflictsOthers(root_name) => {
-                sess.emit_err(SymbolConflictsOthers { span, crate_name: root_name });
+                sess.emit_err(errors::SymbolConflictsCurrent { span, crate_name: root_name });
             }
             CrateError::StableCrateIdCollision(crate_name0, crate_name1) => {
-                sess.emit_err(StableCrateIdCollision { span, crate_name0, crate_name1 });
+                sess.emit_err(errors::StableCrateIdCollision { span, crate_name0, crate_name1 });
             }
             CrateError::DlOpen(s) | CrateError::DlSym(s) => {
-                sess.emit_err(DlError { span, err: s });
+                sess.emit_err(errors::DlError { span, err: s });
             }
             CrateError::LocatorCombined(locator) => {
                 let crate_name = locator.crate_name;
@@ -1012,8 +1003,12 @@ pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
                 if !locator.crate_rejections.via_filename.is_empty() {
                     let mismatches = locator.crate_rejections.via_filename.iter();
                     for CrateMismatch { path, .. } in mismatches {
-                        sess.emit_err(CrateLocationUnknownType { span, path: &path, crate_name });
-                        sess.emit_err(LibFilenameForm {
+                        sess.emit_err(errors::CrateLocationUnknownType {
+                            span,
+                            path: &path,
+                            crate_name,
+                        });
+                        sess.emit_err(errors::LibFilenameForm {
                             span,
                             dll_prefix: &locator.dll_prefix,
                             dll_suffix: &locator.dll_suffix,
@@ -1039,7 +1034,7 @@ pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
                             ));
                         }
                     }
-                    sess.emit_err(NewerCrateVersion {
+                    sess.emit_err(errors::NewerCrateVersion {
                         span,
                         crate_name: crate_name,
                         add_info,
@@ -1055,7 +1050,7 @@ pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
                             path.display(),
                         ));
                     }
-                    sess.emit_err(NoCrateWithTriple {
+                    sess.emit_err(errors::NoCrateWithTriple {
                         span,
                         crate_name,
                         locator_triple: locator.triple.triple(),
@@ -1071,7 +1066,12 @@ pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
                             path.display()
                         ));
                     }
-                    sess.emit_err(FoundStaticlib { span, crate_name, add_info, found_crates });
+                    sess.emit_err(errors::FoundStaticlib {
+                        span,
+                        crate_name,
+                        add_info,
+                        found_crates,
+                    });
                 } else if !locator.crate_rejections.via_version.is_empty() {
                     let mismatches = locator.crate_rejections.via_version.iter();
                     for CrateMismatch { path, got } in mismatches {
@@ -1082,7 +1082,7 @@ pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
                             path.display(),
                         ));
                     }
-                    sess.emit_err(IncompatibleRustc {
+                    sess.emit_err(errors::IncompatibleRustc {
                         span,
                         crate_name,
                         add_info,
@@ -1094,14 +1094,14 @@ pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
                     for CrateMismatch { path: _, got } in locator.crate_rejections.via_invalid {
                         crate_rejections.push(got);
                     }
-                    sess.emit_err(InvalidMetadataFiles {
+                    sess.emit_err(errors::InvalidMetadataFiles {
                         span,
                         crate_name,
                         add_info,
                         crate_rejections,
                     });
                 } else {
-                    sess.emit_err(CannotFindCrate {
+                    sess.emit_err(errors::CannotFindCrate {
                         span,
                         crate_name,
                         add_info,
@@ -1118,7 +1118,7 @@ pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
                 }
             }
             CrateError::NonDylibPlugin(crate_name) => {
-                sess.emit_err(NoDylibPlugin { span, crate_name });
+                sess.emit_err(errors::NoDylibPlugin { span, crate_name });
             }
         }
     }
index a5910100786ec71904c01b8348e026f7f556b8e9..e263fc7483537607483a9da0de99a0f4bdb881d4 100644 (file)
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
-use crate::errors::{
-    AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, EmptyRenamingTarget,
-    FrameworkOnlyWindows, ImportNameTypeForm, ImportNameTypeRaw, ImportNameTypeX86,
-    IncompatibleWasmLink, InvalidLinkModifier, LibFrameworkApple, LinkCfgForm,
-    LinkCfgSinglePredicate, LinkFrameworkApple, LinkKindForm, LinkModifiersForm, LinkNameForm,
-    LinkOrdinalRawDylib, LinkRequiresName, MissingNativeLibrary, MultipleCfgs,
-    MultipleImportNameType, MultipleKindsInLink, MultipleLinkModifiers, MultipleModifiers,
-    MultipleNamesInLink, MultipleRenamings, MultipleWasmImport, NoLinkModOverride, RawDylibNoNul,
-    RenamingNoLink, UnexpectedLinkArg, UnknownImportNameType, UnknownLinkKind, UnknownLinkModifier,
-    UnsupportedAbi, UnsupportedAbiI686, WasmImportForm, WholeArchiveNeedsStatic,
-};
+use crate::errors;
 
 use std::path::PathBuf;
 
@@ -52,7 +42,7 @@ pub fn find_native_static_library(
         }
     }
 
-    sess.emit_fatal(MissingNativeLibrary::new(name, verbatim));
+    sess.emit_fatal(errors::MissingNativeLibrary::new(name, verbatim));
 }
 
 fn find_bundled_library(
@@ -129,26 +119,26 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                 match item.name_or_empty() {
                     sym::name => {
                         if name.is_some() {
-                            sess.emit_err(MultipleNamesInLink { span: item.span() });
+                            sess.emit_err(errors::MultipleNamesInLink { span: item.span() });
                             continue;
                         }
                         let Some(link_name) = item.value_str() else {
-                            sess.emit_err(LinkNameForm { span: item.span() });
+                            sess.emit_err(errors::LinkNameForm { span: item.span() });
                             continue;
                         };
                         let span = item.name_value_literal_span().unwrap();
                         if link_name.is_empty() {
-                            sess.emit_err(EmptyLinkName { span });
+                            sess.emit_err(errors::EmptyLinkName { span });
                         }
                         name = Some((link_name, span));
                     }
                     sym::kind => {
                         if kind.is_some() {
-                            sess.emit_err(MultipleKindsInLink { span: item.span() });
+                            sess.emit_err(errors::MultipleKindsInLink { span: item.span() });
                             continue;
                         }
                         let Some(link_kind) = item.value_str() else {
-                            sess.emit_err(LinkKindForm { span: item.span() });
+                            sess.emit_err(errors::LinkKindForm { span: item.span() });
                             continue;
                         };
 
@@ -158,13 +148,13 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                             "dylib" => NativeLibKind::Dylib { as_needed: None },
                             "framework" => {
                                 if !sess.target.is_like_osx {
-                                    sess.emit_err(LinkFrameworkApple { span });
+                                    sess.emit_err(errors::LinkFrameworkApple { span });
                                 }
                                 NativeLibKind::Framework { as_needed: None }
                             }
                             "raw-dylib" => {
                                 if !sess.target.is_like_windows {
-                                    sess.emit_err(FrameworkOnlyWindows { span });
+                                    sess.emit_err(errors::FrameworkOnlyWindows { span });
                                 } else if !features.raw_dylib && sess.target.arch == "x86" {
                                     feature_err(
                                         &sess.parse_sess,
@@ -177,7 +167,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                                 NativeLibKind::RawDylib
                             }
                             kind => {
-                                sess.emit_err(UnknownLinkKind { span, kind });
+                                sess.emit_err(errors::UnknownLinkKind { span, kind });
                                 continue;
                             }
                         };
@@ -185,26 +175,26 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                     }
                     sym::modifiers => {
                         if modifiers.is_some() {
-                            sess.emit_err(MultipleLinkModifiers { span: item.span() });
+                            sess.emit_err(errors::MultipleLinkModifiers { span: item.span() });
                             continue;
                         }
                         let Some(link_modifiers) = item.value_str() else {
-                            sess.emit_err(LinkModifiersForm { span: item.span() });
+                            sess.emit_err(errors::LinkModifiersForm { span: item.span() });
                             continue;
                         };
                         modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap()));
                     }
                     sym::cfg => {
                         if cfg.is_some() {
-                            sess.emit_err(MultipleCfgs { span: item.span() });
+                            sess.emit_err(errors::MultipleCfgs { span: item.span() });
                             continue;
                         }
                         let Some(link_cfg) = item.meta_item_list() else {
-                            sess.emit_err(LinkCfgForm { span: item.span() });
+                            sess.emit_err(errors::LinkCfgForm { span: item.span() });
                             continue;
                         };
                         let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else {
-                            sess.emit_err(LinkCfgSinglePredicate { span: item.span() });
+                            sess.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
                             continue;
                         };
                         if !features.link_cfg {
@@ -220,26 +210,26 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                     }
                     sym::wasm_import_module => {
                         if wasm_import_module.is_some() {
-                            sess.emit_err(MultipleWasmImport { span: item.span() });
+                            sess.emit_err(errors::MultipleWasmImport { span: item.span() });
                             continue;
                         }
                         let Some(link_wasm_import_module) = item.value_str() else {
-                            sess.emit_err(WasmImportForm { span: item.span() });
+                            sess.emit_err(errors::WasmImportForm { span: item.span() });
                             continue;
                         };
                         wasm_import_module = Some((link_wasm_import_module, item.span()));
                     }
                     sym::import_name_type => {
                         if import_name_type.is_some() {
-                            sess.emit_err(MultipleImportNameType { span: item.span() });
+                            sess.emit_err(errors::MultipleImportNameType { span: item.span() });
                             continue;
                         }
                         let Some(link_import_name_type) = item.value_str() else {
-                            sess.emit_err(ImportNameTypeForm { span: item.span() });
+                            sess.emit_err(errors::ImportNameTypeForm { span: item.span() });
                             continue;
                         };
                         if self.tcx.sess.target.arch != "x86" {
-                            sess.emit_err(ImportNameTypeX86 { span: item.span() });
+                            sess.emit_err(errors::ImportNameTypeX86 { span: item.span() });
                             continue;
                         }
 
@@ -248,7 +238,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                             "noprefix" => PeImportNameType::NoPrefix,
                             "undecorated" => PeImportNameType::Undecorated,
                             import_name_type => {
-                                sess.emit_err(UnknownImportNameType {
+                                sess.emit_err(errors::UnknownImportNameType {
                                     span: item.span(),
                                     import_name_type,
                                 });
@@ -268,7 +258,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                         import_name_type = Some((link_import_name_type, item.span()));
                     }
                     _ => {
-                        sess.emit_err(UnexpectedLinkArg { span: item.span() });
+                        sess.emit_err(errors::UnexpectedLinkArg { span: item.span() });
                     }
                 }
             }
@@ -280,7 +270,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                     let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
                         Some(m) => (m, modifier.starts_with('+')),
                         None => {
-                            sess.emit_err(InvalidLinkModifier { span });
+                            sess.emit_err(errors::InvalidLinkModifier { span });
                             continue;
                         }
                     };
@@ -298,7 +288,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                     }
                     let assign_modifier = |dst: &mut Option<bool>| {
                         if dst.is_some() {
-                            sess.emit_err(MultipleModifiers { span, modifier });
+                            sess.emit_err(errors::MultipleModifiers { span, modifier });
                         } else {
                             *dst = Some(value);
                         }
@@ -308,7 +298,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                             assign_modifier(bundle)
                         }
                         ("bundle", _) => {
-                            sess.emit_err(BundleNeedsStatic { span });
+                            sess.emit_err(errors::BundleNeedsStatic { span });
                         }
 
                         ("verbatim", _) => assign_modifier(&mut verbatim),
@@ -317,7 +307,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                             assign_modifier(whole_archive)
                         }
                         ("whole-archive", _) => {
-                            sess.emit_err(WholeArchiveNeedsStatic { span });
+                            sess.emit_err(errors::WholeArchiveNeedsStatic { span });
                         }
 
                         ("as-needed", Some(NativeLibKind::Dylib { as_needed }))
@@ -326,11 +316,11 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                             assign_modifier(as_needed)
                         }
                         ("as-needed", _) => {
-                            sess.emit_err(AsNeededCompatibility { span });
+                            sess.emit_err(errors::AsNeededCompatibility { span });
                         }
 
                         _ => {
-                            sess.emit_err(UnknownLinkModifier { span, modifier });
+                            sess.emit_err(errors::UnknownLinkModifier { span, modifier });
                         }
                     }
                 }
@@ -338,23 +328,23 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
 
             if let Some((_, span)) = wasm_import_module {
                 if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
-                    sess.emit_err(IncompatibleWasmLink { span });
+                    sess.emit_err(errors::IncompatibleWasmLink { span });
                 }
             } else if name.is_none() {
-                sess.emit_err(LinkRequiresName { span: m.span });
+                sess.emit_err(errors::LinkRequiresName { span: m.span });
             }
 
             // Do this outside of the loop so that `import_name_type` can be specified before `kind`.
             if let Some((_, span)) = import_name_type {
                 if kind != Some(NativeLibKind::RawDylib) {
-                    sess.emit_err(ImportNameTypeRaw { span });
+                    sess.emit_err(errors::ImportNameTypeRaw { span });
                 }
             }
 
             let dll_imports = match kind {
                 Some(NativeLibKind::RawDylib) => {
                     if let Some((name, span)) = name && name.as_str().contains('\0') {
-                        sess.emit_err(RawDylibNoNul { span });
+                        sess.emit_err(errors::RawDylibNoNul { span });
                     }
                     foreign_mod_items
                         .iter()
@@ -383,7 +373,9 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                                 .iter()
                                 .find(|a| a.has_name(sym::link_ordinal))
                                 .unwrap();
-                            sess.emit_err(LinkOrdinalRawDylib { span: link_ordinal_attr.span });
+                            sess.emit_err(errors::LinkOrdinalRawDylib {
+                                span: link_ordinal_attr.span,
+                            });
                         }
                     }
 
@@ -414,7 +406,7 @@ fn process_command_line(&mut self) {
         for lib in &self.tcx.sess.opts.libs {
             if let NativeLibKind::Framework { .. } = lib.kind && !self.tcx.sess.target.is_like_osx {
                 // Cannot check this when parsing options because the target is not yet available.
-                self.tcx.sess.emit_err(LibFrameworkApple);
+                self.tcx.sess.emit_err(errors::LibFrameworkApple);
             }
             if let Some(ref new_name) = lib.new_name {
                 let any_duplicate = self
@@ -423,11 +415,11 @@ fn process_command_line(&mut self) {
                     .filter_map(|lib| lib.name.as_ref())
                     .any(|n| n.as_str() == lib.name);
                 if new_name.is_empty() {
-                    self.tcx.sess.emit_err(EmptyRenamingTarget { lib_name: &lib.name });
+                    self.tcx.sess.emit_err(errors::EmptyRenamingTarget { lib_name: &lib.name });
                 } else if !any_duplicate {
-                    self.tcx.sess.emit_err(RenamingNoLink { lib_name: &lib.name });
+                    self.tcx.sess.emit_err(errors::RenamingNoLink { lib_name: &lib.name });
                 } else if !renames.insert(&lib.name) {
-                    self.tcx.sess.emit_err(MultipleRenamings { lib_name: &lib.name });
+                    self.tcx.sess.emit_err(errors::MultipleRenamings { lib_name: &lib.name });
                 }
             }
         }
@@ -453,12 +445,15 @@ fn process_command_line(&mut self) {
                             // explicit `:rename` in particular.
                             if lib.has_modifiers() || passed_lib.has_modifiers() {
                                 match lib.foreign_module {
-                                    Some(def_id) => self.tcx.sess.emit_err(NoLinkModOverride {
-                                        span: Some(self.tcx.def_span(def_id)),
-                                    }),
-                                    None => {
-                                        self.tcx.sess.emit_err(NoLinkModOverride { span: None })
+                                    Some(def_id) => {
+                                        self.tcx.sess.emit_err(errors::NoLinkModOverride {
+                                            span: Some(self.tcx.def_span(def_id)),
+                                        })
                                     }
+                                    None => self
+                                        .tcx
+                                        .sess
+                                        .emit_err(errors::NoLinkModOverride { span: None }),
                                 };
                             }
                             if passed_lib.kind != NativeLibKind::Unspecified {
@@ -542,14 +537,14 @@ fn build_dll_import(
                     DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
                 }
                 _ => {
-                    self.tcx.sess.emit_fatal(UnsupportedAbiI686 { span: item.span });
+                    self.tcx.sess.emit_fatal(errors::UnsupportedAbiI686 { span: item.span });
                 }
             }
         } else {
             match abi {
                 Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C,
                 _ => {
-                    self.tcx.sess.emit_fatal(UnsupportedAbi { span: item.span });
+                    self.tcx.sess.emit_fatal(errors::UnsupportedAbi { span: item.span });
                 }
             }
         };
index bb2dd290c6d5d1edef0ef7f26ae3f0bbb1793d69..e2b07fad6e782ee24ed5e65f8889a15e1bea3516 100644 (file)
@@ -654,7 +654,7 @@ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
 impl<'a, 'tcx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyArray<T> {
     fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
         let len = decoder.read_usize();
-        if len == 0 { LazyArray::empty() } else { decoder.read_lazy_array(len) }
+        if len == 0 { LazyArray::default() } else { decoder.read_lazy_array(len) }
     }
 }
 
@@ -864,7 +864,7 @@ fn get_variant(self, kind: &DefKind, index: DefIndex, parent_did: DefId) -> ty::
                 .tables
                 .children
                 .get(self, index)
-                .unwrap_or_else(LazyArray::empty)
+                .expect("fields are not encoded for a variant")
                 .decode(self)
                 .map(|index| ty::FieldDef {
                     did: self.local_def_id(index),
@@ -896,7 +896,7 @@ fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<'tcx> {
                 .tables
                 .children
                 .get(self, item_id)
-                .unwrap_or_else(LazyArray::empty)
+                .expect("variants are not encoded for an enum")
                 .decode(self)
                 .filter_map(|index| {
                     let kind = self.def_kind(index);
@@ -1045,7 +1045,7 @@ fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool {
             .tables
             .fn_arg_names
             .get(self, id)
-            .unwrap_or_else(LazyArray::empty)
+            .expect("argument names not encoded for a function")
             .decode((self, sess))
             .nth(0)
             .map_or(false, |ident| ident.name == kw::SelfLower)
@@ -1060,7 +1060,7 @@ fn get_associated_item_def_ids(
             .tables
             .children
             .get(self, id)
-            .unwrap_or_else(LazyArray::empty)
+            .expect("associated items not encoded for an item")
             .decode((self, sess))
             .map(move |child_index| self.local_def_id(child_index))
     }
@@ -1068,13 +1068,12 @@ fn get_associated_item_def_ids(
     fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem {
         let name = self.item_name(id);
 
-        let kind = match self.def_kind(id) {
-            DefKind::AssocConst => ty::AssocKind::Const,
-            DefKind::AssocFn => ty::AssocKind::Fn,
-            DefKind::AssocTy => ty::AssocKind::Type,
+        let (kind, has_self) = match self.def_kind(id) {
+            DefKind::AssocConst => (ty::AssocKind::Const, false),
+            DefKind::AssocFn => (ty::AssocKind::Fn, self.get_fn_has_self_parameter(id, sess)),
+            DefKind::AssocTy => (ty::AssocKind::Type, false),
             _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)),
         };
-        let has_self = self.get_fn_has_self_parameter(id, sess);
         let container = self.root.tables.assoc_container.get(self, id).unwrap();
 
         ty::AssocItem {
@@ -1131,7 +1130,7 @@ fn get_struct_field_names(
             .tables
             .children
             .get(self, id)
-            .unwrap_or_else(LazyArray::empty)
+            .expect("fields not encoded for a struct")
             .decode(self)
             .map(move |index| respan(self.get_span(index, sess), self.item_name(index)))
     }
@@ -1144,7 +1143,7 @@ fn get_struct_field_visibilities(
             .tables
             .children
             .get(self, id)
-            .unwrap_or_else(LazyArray::empty)
+            .expect("fields not encoded for a struct")
             .decode(self)
             .map(move |field_index| self.get_visibility(field_index))
     }
@@ -1159,7 +1158,6 @@ fn get_inherent_implementations_for_type(
                 .tables
                 .inherent_impls
                 .get(self, id)
-                .unwrap_or_else(LazyArray::empty)
                 .decode(self)
                 .map(|index| self.local_def_id(index)),
         )
@@ -1174,7 +1172,6 @@ fn get_inherent_impls(self) -> impl Iterator<Item = (DefId, DefId)> + 'a {
                 .tables
                 .inherent_impls
                 .get(self, ty_index)
-                .unwrap_or_else(LazyArray::empty)
                 .decode(self)
                 .map(move |impl_index| (ty_def_id, self.local_def_id(impl_index)))
         })
@@ -1322,7 +1319,7 @@ fn def_path_hash_unlocked(
     ) -> DefPathHash {
         *def_path_hashes
             .entry(index)
-            .or_insert_with(|| self.root.tables.def_path_hashes.get(self, index).unwrap())
+            .or_insert_with(|| self.root.tables.def_path_hashes.get(self, index))
     }
 
     #[inline]
index 9b1401f4a44dfdf922120faf9bd9f165c902d3c9..07cc84ab95368480a2ec09b80fe0bad29ed63e0c 100644 (file)
@@ -1,6 +1,7 @@
 use crate::creader::{CStore, LoadedMacro};
 use crate::foreign_modules;
 use crate::native_libs;
+use crate::rmeta::table::IsDefault;
 use crate::rmeta::AttrFlags;
 
 use rustc_ast as ast;
@@ -88,6 +89,14 @@ macro_rules! provide_one {
             }
         }
     };
+    ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_defaulted_array }) => {
+        provide_one! {
+            $tcx, $def_id, $other, $cdata, $name => {
+                let lazy = $cdata.root.tables.$name.get($cdata, $def_id.index);
+                if lazy.is_default() { &[] } else { $tcx.arena.alloc_from_iter(lazy.decode(($cdata, $tcx))) }
+            }
+        }
+    };
     ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_direct }) => {
         provide_one! {
             $tcx, $def_id, $other, $cdata, $name => {
@@ -187,10 +196,10 @@ fn into_args(self) -> (DefId, SimplifiedType) {
 }
 
 provide! { tcx, def_id, other, cdata,
-    explicit_item_bounds => { table }
+    explicit_item_bounds => { table_defaulted_array }
     explicit_predicates_of => { table }
     generics_of => { table }
-    inferred_outlives_of => { table }
+    inferred_outlives_of => { table_defaulted_array }
     super_predicates_of => { table }
     type_of => { table }
     variances_of => { table }
index 9d8f14058f681203548cd2a703b3556b5d6c7129..85e9ae9a98302bb780f1866295e0768970998982 100644 (file)
@@ -76,13 +76,13 @@ pub(super) struct EncodeContext<'a, 'tcx> {
     symbol_table: FxHashMap<Symbol, usize>,
 }
 
-/// If the current crate is a proc-macro, returns early with `LazyArray::empty()`.
+/// If the current crate is a proc-macro, returns early with `LazyArray::default()`.
 /// This is useful for skipping the encoding of things that aren't needed
 /// for proc-macro crates.
 macro_rules! empty_proc_macro {
     ($self:ident) => {
         if $self.is_proc_macro {
-            return LazyArray::empty();
+            return LazyArray::default();
         }
     };
 }
@@ -365,21 +365,31 @@ fn encode_alloc_id(&mut self, alloc_id: &rustc_middle::mir::interpret::AllocId)
     }
 }
 
-// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would
+// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_value($value))`, which would
 // normally need extra variables to avoid errors about multiple mutable borrows.
 macro_rules! record {
     ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
         {
             let value = $value;
             let lazy = $self.lazy(value);
-            $self.$tables.$table.set($def_id.index, lazy);
+            $self.$tables.$table.set_some($def_id.index, lazy);
         }
     }};
 }
 
-// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would
+// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_value($value))`, which would
 // normally need extra variables to avoid errors about multiple mutable borrows.
 macro_rules! record_array {
+    ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
+        {
+            let value = $value;
+            let lazy = $self.lazy_array(value);
+            $self.$tables.$table.set_some($def_id.index, lazy);
+        }
+    }};
+}
+
+macro_rules! record_defaulted_array {
     ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
         {
             let value = $value;
@@ -467,13 +477,13 @@ fn encode_def_path_table(&mut self) {
             {
                 let def_key = self.lazy(table.def_key(def_index));
                 let def_path_hash = table.def_path_hash(def_index);
-                self.tables.def_keys.set(def_index, def_key);
+                self.tables.def_keys.set_some(def_index, def_key);
                 self.tables.def_path_hashes.set(def_index, def_path_hash);
             }
         } else {
             for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() {
                 let def_key = self.lazy(def_key);
-                self.tables.def_keys.set(def_index, def_key);
+                self.tables.def_keys.set_some(def_index, def_key);
                 self.tables.def_path_hashes.set(def_index, *def_path_hash);
             }
         }
@@ -548,7 +558,7 @@ fn encode_source_map(&mut self) -> LazyTable<u32, Option<LazyValue<rustc_span::S
 
             let on_disk_index: u32 =
                 on_disk_index.try_into().expect("cannot export more than U32_MAX files");
-            adapted.set(on_disk_index, self.lazy(source_file));
+            adapted.set_some(on_disk_index, self.lazy(source_file));
         }
 
         adapted.encode(&mut self.opaque)
@@ -1147,9 +1157,7 @@ fn encode_attrs(&mut self, def_id: LocalDefId) {
         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);
-        }
+        self.tables.attr_flags.set(def_id.local_def_index, attr_flags);
     }
 
     fn encode_def_ids(&mut self) {
@@ -1161,7 +1169,7 @@ fn encode_def_ids(&mut self) {
             let def_id = local_id.to_def_id();
             let def_kind = tcx.opt_def_kind(local_id);
             let Some(def_kind) = def_kind else { continue };
-            self.tables.opt_def_kind.set(def_id.index, def_kind);
+            self.tables.opt_def_kind.set_some(def_id.index, def_kind);
             let def_span = tcx.def_span(local_id);
             record!(self.tables.def_span[def_id] <- def_span);
             self.encode_attrs(local_id);
@@ -1192,9 +1200,7 @@ fn encode_def_ids(&mut self) {
                 record!(self.tables.generics_of[def_id] <- g);
                 record!(self.tables.explicit_predicates_of[def_id] <- self.tcx.explicit_predicates_of(def_id));
                 let inferred_outlives = self.tcx.inferred_outlives_of(def_id);
-                if !inferred_outlives.is_empty() {
-                    record_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
-                }
+                record_defaulted_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
             }
             if should_encode_type(tcx, local_id, def_kind) {
                 record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id));
@@ -1215,15 +1221,12 @@ fn encode_def_ids(&mut self) {
                 record!(self.tables.trait_impl_trait_tys[def_id] <- table);
             }
         }
+
         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;
-            }
-            record_array!(self.tables.inherent_impls[def_id.to_def_id()] <- implementations.iter().map(|&def_id| {
+        for (def_id, impls) in inherent_impls {
+            record_defaulted_array!(self.tables.inherent_impls[def_id.to_def_id()] <- impls.iter().map(|def_id| {
                 assert!(def_id.is_local());
                 def_id.index
             }));
@@ -1264,14 +1267,14 @@ fn encode_info_for_adt(&mut self, def_id: DefId) {
             };
             record!(self.tables.variant_data[variant.def_id] <- data);
 
-            self.tables.constness.set(variant.def_id.index, hir::Constness::Const);
+            self.tables.constness.set_some(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
             }));
 
             if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor {
-                self.tables.constness.set(ctor_def_id.index, hir::Constness::Const);
+                self.tables.constness.set_some(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
@@ -1332,9 +1335,7 @@ fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) {
     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);
-        if !bounds.is_empty() {
-            record_array!(self.tables.explicit_item_bounds[def_id] <- bounds);
-        }
+        record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds);
     }
 
     fn encode_info_for_trait_item(&mut self, def_id: DefId) {
@@ -1342,16 +1343,16 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) {
         let tcx = self.tcx;
 
         let impl_defaultness = tcx.impl_defaultness(def_id.expect_local());
-        self.tables.impl_defaultness.set(def_id.index, impl_defaultness);
+        self.tables.impl_defaultness.set_some(def_id.index, impl_defaultness);
         let trait_item = tcx.associated_item(def_id);
-        self.tables.assoc_container.set(def_id.index, trait_item.container);
+        self.tables.assoc_container.set_some(def_id.index, trait_item.container);
 
         match trait_item.kind {
             ty::AssocKind::Const => {}
             ty::AssocKind::Fn => {
                 record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id));
-                self.tables.asyncness.set(def_id.index, tcx.asyncness(def_id));
-                self.tables.constness.set(def_id.index, hir::Constness::NotConst);
+                self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id));
+                self.tables.constness.set_some(def_id.index, hir::Constness::NotConst);
             }
             ty::AssocKind::Type => {
                 self.encode_explicit_item_bounds(def_id);
@@ -1367,14 +1368,14 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
         let tcx = self.tcx;
 
         let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
-        self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness);
+        self.tables.impl_defaultness.set_some(def_id.index, ast_item.defaultness);
         let impl_item = self.tcx.associated_item(def_id);
-        self.tables.assoc_container.set(def_id.index, impl_item.container);
+        self.tables.assoc_container.set_some(def_id.index, impl_item.container);
 
         match impl_item.kind {
             ty::AssocKind::Fn => {
                 let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
-                self.tables.asyncness.set(def_id.index, sig.header.asyncness);
+                self.tables.asyncness.set_some(def_id.index, sig.header.asyncness);
                 record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
                 // Can be inside `impl const Trait`, so using sig.header.constness is not reliable
                 let constness = if self.tcx.is_const_fn_raw(def_id) {
@@ -1382,18 +1383,16 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
                 } else {
                     hir::Constness::NotConst
                 };
-                self.tables.constness.set(def_id.index, constness);
+                self.tables.constness.set_some(def_id.index, constness);
             }
             ty::AssocKind::Const | ty::AssocKind::Type => {}
         }
         if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
-            self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into());
+            self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into());
         }
         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_nullable(def_id.index, true);
-            }
+            self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
         }
     }
 
@@ -1522,14 +1521,12 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
 
         match item.kind {
             hir::ItemKind::Fn(ref sig, .., body) => {
-                self.tables.asyncness.set(def_id.index, sig.header.asyncness);
+                self.tables.asyncness.set_some(def_id.index, sig.header.asyncness);
                 record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
-                self.tables.constness.set(def_id.index, sig.header.constness);
+                self.tables.constness.set_some(def_id.index, sig.header.constness);
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
-                if macro_def.macro_rules {
-                    self.tables.is_macro_rules.set_nullable(def_id.index, true);
-                }
+                self.tables.is_macro_rules.set(def_id.index, macro_def.macro_rules);
                 record!(self.tables.macro_definition[def_id] <- &*macro_def.body);
             }
             hir::ItemKind::Mod(ref m) => {
@@ -1537,20 +1534,20 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
             }
             hir::ItemKind::OpaqueTy(ref opaque) => {
                 self.encode_explicit_item_bounds(def_id);
-                if matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) {
-                    self.tables.is_type_alias_impl_trait.set_nullable(def_id.index, true);
-                }
+                self.tables
+                    .is_type_alias_impl_trait
+                    .set(def_id.index, matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias));
             }
             hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
-                self.tables.impl_defaultness.set(def_id.index, *defaultness);
-                self.tables.constness.set(def_id.index, *constness);
+                self.tables.impl_defaultness.set_some(def_id.index, *defaultness);
+                self.tables.constness.set_some(def_id.index, *constness);
 
                 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) {
                         if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) {
-                            self.tables.impl_parent.set(def_id.index, parent.into());
+                            self.tables.impl_parent.set_some(def_id.index, parent.into());
                         }
                     }
 
@@ -1564,7 +1561,7 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
                 }
 
                 let polarity = self.tcx.impl_polarity(def_id);
-                self.tables.impl_polarity.set(def_id.index, polarity);
+                self.tables.impl_polarity.set_some(def_id.index, polarity);
             }
             hir::ItemKind::Trait(..) => {
                 let trait_def = self.tcx.trait_def(def_id);
@@ -1601,9 +1598,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_nullable(def_id.index, true);
-            }
+            self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
         }
         if let hir::ItemKind::Impl { .. } = item.kind {
             if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) {
@@ -1650,7 +1645,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);
+                self.tables.constness.set_some(def_id.to_def_id().index, constness);
                 record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder(substs.as_closure().sig()));
             }
 
@@ -1678,12 +1673,12 @@ fn encode_hygiene(&mut self) -> (SyntaxContextTable, ExpnDataTable, ExpnHashTabl
         self.hygiene_ctxt.encode(
             &mut (&mut *self, &mut syntax_contexts, &mut expn_data_table, &mut expn_hash_table),
             |(this, syntax_contexts, _, _), index, ctxt_data| {
-                syntax_contexts.set(index, this.lazy(ctxt_data));
+                syntax_contexts.set_some(index, this.lazy(ctxt_data));
             },
             |(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| {
                 if let Some(index) = index.as_local() {
-                    expn_data_table.set(index.as_raw(), this.lazy(expn_data));
-                    expn_hash_table.set(index.as_raw(), this.lazy(hash));
+                    expn_data_table.set_some(index.as_raw(), this.lazy(expn_data));
+                    expn_hash_table.set_some(index.as_raw(), this.lazy(hash));
                 }
             },
         );
@@ -1708,10 +1703,10 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
             let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans();
             for (i, span) in spans.into_iter().enumerate() {
                 let span = self.lazy(span);
-                self.tables.proc_macro_quoted_spans.set(i, span);
+                self.tables.proc_macro_quoted_spans.set_some(i, span);
             }
 
-            self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
+            self.tables.opt_def_kind.set_some(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
             record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
             self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local());
             let vis = tcx.local_visibility(CRATE_DEF_ID).map_id(|def_id| def_id.local_def_index);
@@ -1753,8 +1748,8 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
                 def_key.disambiguated_data.data = DefPathData::MacroNs(name);
 
                 let def_id = id.to_def_id();
-                self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind));
-                self.tables.proc_macro.set(def_id.index, macro_kind);
+                self.tables.opt_def_kind.set_some(def_id.index, DefKind::Macro(macro_kind));
+                self.tables.proc_macro.set_some(def_id.index, macro_kind);
                 self.encode_attrs(id);
                 record!(self.tables.def_keys[def_id] <- def_key);
                 record!(self.tables.def_ident_span[def_id] <- span);
@@ -1969,7 +1964,7 @@ fn encode_dylib_dependency_formats(&mut self) -> LazyArray<Option<LinkagePrefere
                 Linkage::Static => Some(LinkagePreference::RequireStatic),
             }));
         }
-        LazyArray::empty()
+        LazyArray::default()
     }
 
     fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignItem<'_>) {
@@ -1979,22 +1974,20 @@ fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignIt
 
         match nitem.kind {
             hir::ForeignItemKind::Fn(_, ref names, _) => {
-                self.tables.asyncness.set(def_id.index, hir::IsAsync::NotAsync);
+                self.tables.asyncness.set_some(def_id.index, hir::IsAsync::NotAsync);
                 record_array!(self.tables.fn_arg_names[def_id] <- *names);
                 let constness = if self.tcx.is_const_fn_raw(def_id) {
                     hir::Constness::Const
                 } else {
                     hir::Constness::NotConst
                 };
-                self.tables.constness.set(def_id.index, constness);
+                self.tables.constness.set_some(def_id.index, constness);
                 record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
             }
             hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => {}
         }
         if let hir::ForeignItemKind::Fn(..) = nitem.kind {
-            if tcx.is_intrinsic(def_id) {
-                self.tables.is_intrinsic.set_nullable(def_id.index, true);
-            }
+            self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
         }
     }
 }
index 37af9e64e9a3da5002ee527d5b6f655d05366506..a74aa381d9eb829097c219163db4f04750a3d098 100644 (file)
@@ -115,14 +115,16 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> {
     type Value<'tcx> = LazyArray<T::Value<'tcx>>;
 }
 
+impl<T> Default for LazyArray<T> {
+    fn default() -> LazyArray<T> {
+        LazyArray::from_position_and_num_elems(NonZeroUsize::new(1).unwrap(), 0)
+    }
+}
+
 impl<T> LazyArray<T> {
     fn from_position_and_num_elems(position: NonZeroUsize, num_elems: usize) -> LazyArray<T> {
         LazyArray { position, num_elems, _marker: PhantomData }
     }
-
-    fn empty() -> LazyArray<T> {
-        LazyArray::from_position_and_num_elems(NonZeroUsize::new(1).unwrap(), 0)
-    }
 }
 
 /// A list of lazily-decoded values, with the added capability of random access.
@@ -316,7 +318,7 @@ pub(crate) struct IncoherentImpls {
 /// Define `LazyTables` and `TableBuilders` at the same time.
 macro_rules! define_tables {
     (
-        - nullable: $($name1:ident: Table<$IDX1:ty, $T1:ty>,)+
+        - defaulted: $($name1:ident: Table<$IDX1:ty, $T1:ty>,)+
         - optional: $($name2:ident: Table<$IDX2:ty, $T2:ty>,)+
     ) => {
         #[derive(MetadataEncodable, MetadataDecodable)]
@@ -343,11 +345,15 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
 }
 
 define_tables! {
-- nullable:
+- defaulted:
     is_intrinsic: Table<DefIndex, bool>,
     is_macro_rules: Table<DefIndex, bool>,
     is_type_alias_impl_trait: Table<DefIndex, bool>,
     attr_flags: Table<DefIndex, AttrFlags>,
+    def_path_hashes: Table<DefIndex, DefPathHash>,
+    explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
+    inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
+    inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
 
 - optional:
     attributes: Table<DefIndex, LazyArray<ast::Attribute>>,
@@ -360,12 +366,8 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>,
     lookup_default_body_stability: Table<DefIndex, LazyValue<attr::DefaultBodyStability>>,
     lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
-    // As an optimization, a missing entry indicates an empty `&[]`.
-    explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
     explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
     generics_of: Table<DefIndex, LazyValue<ty::Generics>>,
-    // As an optimization, a missing entry indicates an empty `&[]`.
-    inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     super_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
     type_of: Table<DefIndex, LazyValue<Ty<'static>>>,
     variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
@@ -393,7 +395,6 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     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>>,
     unused_generic_params: Table<DefIndex, LazyValue<UnusedGenericParams>>,
     params_in_repr: Table<DefIndex, LazyValue<BitSet<u32>>>,
@@ -403,7 +404,6 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     // `DefPathTable` up front, since we may only ever use a few
     // definitions from any given crate.
     def_keys: Table<DefIndex, LazyValue<DefKey>>,
-    def_path_hashes: Table<DefIndex, DefPathHash>,
     proc_macro_quoted_spans: Table<usize, LazyValue<Span>>,
     generator_diagnostic_data: Table<DefIndex, LazyValue<GeneratorDiagnosticData<'static>>>,
     variant_data: Table<DefIndex, LazyValue<VariantData>>,
index 70dbf6476e2fab40d8c4a89b575528b3bd3f6f6b..99bec570600a0faae76c4afb1479ce834e1702c1 100644 (file)
 use std::marker::PhantomData;
 use std::num::NonZeroUsize;
 
+pub(super) trait IsDefault: Default {
+    fn is_default(&self) -> bool;
+}
+
+impl<T> IsDefault for Option<T> {
+    fn is_default(&self) -> bool {
+        self.is_none()
+    }
+}
+
+impl IsDefault for AttrFlags {
+    fn is_default(&self) -> bool {
+        self.is_empty()
+    }
+}
+
+impl IsDefault for bool {
+    fn is_default(&self) -> bool {
+        !self
+    }
+}
+
+impl IsDefault for u32 {
+    fn is_default(&self) -> bool {
+        *self == 0
+    }
+}
+
+impl<T> IsDefault for LazyArray<T> {
+    fn is_default(&self) -> bool {
+        self.num_elems == 0
+    }
+}
+
+impl IsDefault for DefPathHash {
+    fn is_default(&self) -> bool {
+        self.0 == Fingerprint::ZERO
+    }
+}
+
 /// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
 /// Used mainly for Lazy positions and lengths.
 /// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
 /// but this has no impact on safety.
-pub(super) trait FixedSizeEncoding: Default {
+pub(super) trait FixedSizeEncoding: IsDefault {
     /// This should be `[u8; BYTE_LEN]`;
     /// Cannot use an associated `const BYTE_LEN: usize` instead due to const eval limitations.
     type ByteArray;
@@ -23,6 +63,8 @@ pub(super) trait FixedSizeEncoding: Default {
     fn write_to_bytes(self, b: &mut Self::ByteArray);
 }
 
+/// This implementation is not used generically, but for reading/writing
+/// concrete `u32` fields in `Lazy*` structures, which may be zero.
 impl FixedSizeEncoding for u32 {
     type ByteArray = [u8; 4];
 
@@ -58,7 +100,7 @@ impl FixedSizeEncoding for Option<$ty> {
             fn write_to_bytes(self, b: &mut [u8;1]) {
                 use $ty::*;
                 b[0] = match self {
-                    None => 0,
+                    None => unreachable!(),
                     $(Some($($pat)*) => 1 + ${index()},)*
                 }
             }
@@ -155,20 +197,18 @@ impl FixedSizeEncoding for Option<$ty> {
 }
 
 // We directly encode `DefPathHash` because a `LazyValue` would incur a 25% cost.
-impl FixedSizeEncoding for Option<DefPathHash> {
+impl FixedSizeEncoding for DefPathHash {
     type ByteArray = [u8; 16];
 
     #[inline]
     fn from_bytes(b: &[u8; 16]) -> Self {
-        Some(DefPathHash(Fingerprint::from_le_bytes(*b)))
+        DefPathHash(Fingerprint::from_le_bytes(*b))
     }
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 16]) {
-        let Some(DefPathHash(fingerprint)) = self else {
-            panic!("Trying to encode absent DefPathHash.")
-        };
-        *b = fingerprint.to_le_bytes();
+        debug_assert!(!self.is_default());
+        *b = self.0.to_le_bytes();
     }
 }
 
@@ -179,17 +219,17 @@ impl FixedSizeEncoding for Option<RawDefId> {
     #[inline]
     fn from_bytes(b: &[u8; 8]) -> Self {
         let krate = u32::from_le_bytes(b[0..4].try_into().unwrap());
-        let index = u32::from_le_bytes(b[4..8].try_into().unwrap());
         if krate == 0 {
             return None;
         }
+        let index = u32::from_le_bytes(b[4..8].try_into().unwrap());
         Some(RawDefId { krate: krate - 1, index })
     }
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 8]) {
         match self {
-            None => *b = [0; 8],
+            None => unreachable!(),
             Some(RawDefId { krate, index }) => {
                 // CrateNum is less than `CrateNum::MAX_AS_U32`.
                 debug_assert!(krate < u32::MAX);
@@ -210,6 +250,7 @@ impl FixedSizeEncoding for AttrFlags {
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 1]) {
+        debug_assert!(!self.is_default());
         b[0] = self.bits();
     }
 }
@@ -224,6 +265,7 @@ impl FixedSizeEncoding for bool {
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 1]) {
+        debug_assert!(!self.is_default());
         b[0] = self as u8
     }
 }
@@ -242,34 +284,72 @@ impl<T> FixedSizeEncoding for Option<LazyValue<T>> {
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 4]) {
-        let position = self.map_or(0, |lazy| lazy.position.get());
+        match self {
+            None => unreachable!(),
+            Some(lazy) => {
+                let position = lazy.position.get();
+                let position: u32 = position.try_into().unwrap();
+                position.write_to_bytes(b)
+            }
+        }
+    }
+}
+
+impl<T> LazyArray<T> {
+    #[inline]
+    fn write_to_bytes_impl(self, b: &mut [u8; 8]) {
+        let ([position_bytes, meta_bytes],[])= b.as_chunks_mut::<4>() else { panic!() };
+
+        let position = self.position.get();
         let position: u32 = position.try_into().unwrap();
-        position.write_to_bytes(b)
+        position.write_to_bytes(position_bytes);
+
+        let len = self.num_elems;
+        let len: u32 = len.try_into().unwrap();
+        len.write_to_bytes(meta_bytes);
+    }
+
+    fn from_bytes_impl(position_bytes: &[u8; 4], meta_bytes: &[u8; 4]) -> Option<LazyArray<T>> {
+        let position = NonZeroUsize::new(u32::from_bytes(position_bytes) as usize)?;
+        let len = u32::from_bytes(meta_bytes) as usize;
+        Some(LazyArray::from_position_and_num_elems(position, len))
     }
 }
 
-impl<T> FixedSizeEncoding for Option<LazyArray<T>> {
+impl<T> FixedSizeEncoding for LazyArray<T> {
     type ByteArray = [u8; 8];
 
     #[inline]
     fn from_bytes(b: &[u8; 8]) -> Self {
-        let ([ref position_bytes, ref meta_bytes],[])= b.as_chunks::<4>() else { panic!() };
-        let position = NonZeroUsize::new(u32::from_bytes(position_bytes) as usize)?;
-        let len = u32::from_bytes(meta_bytes) as usize;
-        Some(LazyArray::from_position_and_num_elems(position, len))
+        let ([position_bytes, meta_bytes],[])= b.as_chunks::<4>() else { panic!() };
+        if *meta_bytes == [0; 4] {
+            return Default::default();
+        }
+        LazyArray::from_bytes_impl(position_bytes, meta_bytes).unwrap()
     }
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 8]) {
-        let ([ref mut position_bytes, ref mut meta_bytes],[])= b.as_chunks_mut::<4>() else { panic!() };
+        assert!(!self.is_default());
+        self.write_to_bytes_impl(b)
+    }
+}
 
-        let position = self.map_or(0, |lazy| lazy.position.get());
-        let position: u32 = position.try_into().unwrap();
-        position.write_to_bytes(position_bytes);
+impl<T> FixedSizeEncoding for Option<LazyArray<T>> {
+    type ByteArray = [u8; 8];
 
-        let len = self.map_or(0, |lazy| lazy.num_elems);
-        let len: u32 = len.try_into().unwrap();
-        len.write_to_bytes(meta_bytes);
+    #[inline]
+    fn from_bytes(b: &[u8; 8]) -> Self {
+        let ([position_bytes, meta_bytes],[])= b.as_chunks::<4>() else { panic!() };
+        LazyArray::from_bytes_impl(position_bytes, meta_bytes)
+    }
+
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 8]) {
+        match self {
+            None => unreachable!(),
+            Some(lazy) => lazy.write_to_bytes_impl(b),
+        }
     }
 }
 
@@ -289,20 +369,27 @@ impl<I: Idx, const N: usize, T> TableBuilder<I, Option<T>>
 where
     Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
 {
-    pub(crate) fn set(&mut self, i: I, value: T) {
-        self.set_nullable(i, Some(value))
+    pub(crate) fn set_some(&mut self, i: I, value: T) {
+        self.set(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]);
-        value.write_to_bytes(&mut self.blocks[i]);
+    /// Sets the table value if it is not default.
+    /// ATTENTION: For optimization default values are simply ignored by this function, because
+    /// right now metadata tables never need to reset non-default values to default. If such need
+    /// arises in the future then a new method (e.g. `clear` or `reset`) will need to be introduced
+    /// for doing that explicitly.
+    pub(crate) fn set(&mut self, i: I, value: T) {
+        if !value.is_default() {
+            // 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]);
+            value.write_to_bytes(&mut self.blocks[i]);
+        }
     }
 
     pub(crate) fn encode(&self, buf: &mut FileEncoder) -> LazyTable<I, T> {
@@ -331,10 +418,7 @@ pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(&self, metadata: M, i: I) ->
         let start = self.position.get();
         let bytes = &metadata.blob()[start..start + self.encoded_size];
         let (bytes, []) = bytes.as_chunks::<N>() else { panic!() };
-        match bytes.get(i.index()) {
-            Some(bytes) => FixedSizeEncoding::from_bytes(bytes),
-            None => FixedSizeEncoding::from_bytes(&[0; N]),
-        }
+        bytes.get(i.index()).map_or_else(Default::default, FixedSizeEncoding::from_bytes)
     }
 
     /// Size of the table in entries, including possible gaps.
index 72f4f6e649bcf178e51017fc2fb8a57bb81b52a0..2ba7ec5b151929ebd00d96a0f2d7355778f43f0a 100644 (file)
@@ -112,6 +112,7 @@ macro_rules! arena_types {
 
             [decode] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap<rustc_hir::def_id::DefId, rustc_middle::ty::Ty<'tcx>>,
             [] bit_set_u32: rustc_index::bit_set::BitSet<u32>,
+            [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>,
         ]);
     )
 }
index 6e130bbf7d8284403fccb3af90c7e1a229a08c86..d6f20a8fc06ec563f960c59e604c96b89464c2b7 100644 (file)
@@ -324,10 +324,8 @@ pub fn unchecked_rebind<W>(self, value: W) -> Canonical<'tcx, W> {
     }
 }
 
-pub type QueryOutlivesConstraint<'tcx> = (
-    ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>,
-    ConstraintCategory<'tcx>,
-);
+pub type QueryOutlivesConstraint<'tcx> =
+    (ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
 
 TrivialTypeTraversalAndLiftImpls! {
     for <'tcx> {
index bd9cd53e11578b2442d0a981d1c3b6dd7fe1a8a2..f22c0dbc60d9d0f6a7114f0db7f87b550737eaca 100644 (file)
@@ -430,8 +430,10 @@ pub enum ResourceExhaustionInfo {
     ///
     /// The exact limit is set by the `const_eval_limit` attribute.
     StepLimitReached,
-    /// There is not enough memory to perform an allocation.
+    /// There is not enough memory (on the host) to perform an allocation.
     MemoryExhausted,
+    /// The address space (of the target) is full.
+    AddressSpaceFull,
 }
 
 impl fmt::Display for ResourceExhaustionInfo {
@@ -447,6 +449,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             MemoryExhausted => {
                 write!(f, "tried to allocate more memory than available to compiler")
             }
+            AddressSpaceFull => {
+                write!(f, "there are no more free addresses in the address space")
+            }
         }
     }
 }
index 05a9ec5e6d04a5bca66b64c4795984223ebcd2d7..10ac7e0d39af6ca89d849eb539a9410a9dd9c7f1 100644 (file)
@@ -2098,10 +2098,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
                     AggregateKind::Closure(def_id, substs) => ty::tls::with(|tcx| {
                         let name = if tcx.sess.opts.unstable_opts.span_free_formats {
                             let substs = tcx.lift(substs).unwrap();
-                            format!(
-                                "[closure@{}]",
-                                tcx.def_path_str_with_substs(def_id.to_def_id(), substs),
-                            )
+                            format!("[closure@{}]", tcx.def_path_str_with_substs(def_id, substs),)
                         } else {
                             let span = tcx.def_span(def_id);
                             format!(
@@ -2112,11 +2109,17 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
                         let mut struct_fmt = fmt.debug_struct(&name);
 
                         // FIXME(project-rfc-2229#48): This should be a list of capture names/places
-                        if let Some(upvars) = tcx.upvars_mentioned(def_id) {
+                        if let Some(def_id) = def_id.as_local()
+                            && let Some(upvars) = tcx.upvars_mentioned(def_id)
+                        {
                             for (&var_id, place) in iter::zip(upvars.keys(), places) {
                                 let var_name = tcx.hir().name(var_id);
                                 struct_fmt.field(var_name.as_str(), place);
                             }
+                        } else {
+                            for (index, place) in places.iter().enumerate() {
+                                struct_fmt.field(&format!("{index}"), place);
+                            }
                         }
 
                         struct_fmt.finish()
@@ -2127,11 +2130,17 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
                         let mut struct_fmt = fmt.debug_struct(&name);
 
                         // FIXME(project-rfc-2229#48): This should be a list of capture names/places
-                        if let Some(upvars) = tcx.upvars_mentioned(def_id) {
+                        if let Some(def_id) = def_id.as_local()
+                            && let Some(upvars) = tcx.upvars_mentioned(def_id)
+                        {
                             for (&var_id, place) in iter::zip(upvars.keys(), places) {
                                 let var_name = tcx.hir().name(var_id);
                                 struct_fmt.field(var_name.as_str(), place);
                             }
+                        } else {
+                            for (index, place) in places.iter().enumerate() {
+                                struct_fmt.field(&format!("{index}"), place);
+                            }
                         }
 
                         struct_fmt.finish()
index 549bc65d6d79c7858a144fd038c107f1a07d85e5..66ee68187896f54d7466442a18cb55a76d1270d5 100644 (file)
@@ -1203,10 +1203,8 @@ pub enum AggregateKind<'tcx> {
     /// active field index would identity the field `c`
     Adt(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>),
 
-    // Note: We can use LocalDefId since closures and generators a deaggregated
-    // before codegen.
-    Closure(LocalDefId, SubstsRef<'tcx>),
-    Generator(LocalDefId, SubstsRef<'tcx>, hir::Movability),
+    Closure(DefId, SubstsRef<'tcx>),
+    Generator(DefId, SubstsRef<'tcx>, hir::Movability),
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
index 599f0b9d3fab4de99f30f25ba9fd1bf6774ed3ab..b5e0b88bbe52dbf79ff94f109d4b52f960d17311 100644 (file)
@@ -205,9 +205,9 @@ pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
                 AggregateKind::Adt(did, _, substs, _, _) => {
                     tcx.bound_type_of(did).subst(tcx, substs)
                 }
-                AggregateKind::Closure(did, substs) => tcx.mk_closure(did.to_def_id(), substs),
+                AggregateKind::Closure(did, substs) => tcx.mk_closure(did, substs),
                 AggregateKind::Generator(did, substs, movability) => {
-                    tcx.mk_generator(did.to_def_id(), substs, movability)
+                    tcx.mk_generator(did, substs, movability)
                 }
             },
             Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty),
index 4cebe416354a928fd423f0cd4c56f68af5d3c253..7aa9282b9beceb88301dc76df08af1845b4a101b 100644 (file)
     query upstream_monomorphizations_for(def_id: DefId)
         -> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>>
     {
-        arena_cache
         desc { |tcx|
             "collecting available upstream monomorphizations for `{}`",
             tcx.def_path_str(def_id),
index cf3dce48064923a0b582c25ca028827c673eecdf..c528929e7561dacb8572e7185a1d2dd3a6bacb5d 100644 (file)
@@ -5,6 +5,7 @@
 mod chalk;
 pub mod query;
 pub mod select;
+pub mod solve;
 pub mod specialization_graph;
 mod structural_impls;
 pub mod util;
@@ -474,6 +475,8 @@ pub enum WellFormedLoc {
 pub struct ImplDerivedObligationCause<'tcx> {
     pub derived: DerivedObligationCause<'tcx>,
     pub impl_def_id: DefId,
+    /// The index of the derived predicate in the parent impl's predicates.
+    pub impl_def_predicate_index: Option<usize>,
     pub span: Span,
 }
 
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
new file mode 100644 (file)
index 0000000..63f9c32
--- /dev/null
@@ -0,0 +1,55 @@
+use std::ops::ControlFlow;
+
+use rustc_data_structures::intern::Interned;
+
+use crate::ty::{FallibleTypeFolder, Ty, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor};
+
+#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
+pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>);
+
+impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> {
+    type Target = ExternalConstraintsData<'tcx>;
+
+    fn deref(&self) -> &Self::Target {
+        &*self.0
+    }
+}
+
+/// Additional constraints returned on success.
+#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)]
+pub struct ExternalConstraintsData<'tcx> {
+    // FIXME: implement this.
+    pub regions: (),
+    pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>,
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ExternalConstraints<'tcx> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(FallibleTypeFolder::tcx(folder).intern_external_constraints(ExternalConstraintsData {
+            regions: (),
+            opaque_types: self
+                .opaque_types
+                .iter()
+                .map(|opaque| opaque.try_fold_with(folder))
+                .collect::<Result<_, F::Error>>()?,
+        }))
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+        TypeFolder::tcx(folder).intern_external_constraints(ExternalConstraintsData {
+            regions: (),
+            opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(),
+        })
+    }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for ExternalConstraints<'tcx> {
+    fn visit_with<V: TypeVisitor<'tcx>>(
+        &self,
+        visitor: &mut V,
+    ) -> std::ops::ControlFlow<V::BreakTy> {
+        self.regions.visit_with(visitor)?;
+        self.opaque_types.visit_with(visitor)?;
+        ControlFlow::Continue(())
+    }
+}
index f98172e420162c4ae6aecc0b8fd247e3589757f2..9205a8a0ffed801859efae523f76cceaa6aa4b60 100644 (file)
@@ -17,6 +17,7 @@
 };
 use crate::thir::Thir;
 use crate::traits;
+use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData};
 use crate::ty::query::{self, TyCtxtAt};
 use crate::ty::{
     self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, DefIdTree, FloatTy, FloatVar,
@@ -148,6 +149,7 @@ pub struct CtxtInterners<'tcx> {
     bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
     layout: InternedSet<'tcx, LayoutS<VariantIdx>>,
     adt_def: InternedSet<'tcx, AdtDefData>,
+    external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>,
 }
 
 impl<'tcx> CtxtInterners<'tcx> {
@@ -169,6 +171,7 @@ fn new(arena: &'tcx WorkerLocal<Arena<'tcx>>) -> CtxtInterners<'tcx> {
             bound_variable_kinds: Default::default(),
             layout: Default::default(),
             adt_def: Default::default(),
+            external_constraints: Default::default(),
         }
     }
 
@@ -1449,6 +1452,7 @@ pub fn $method(self, v: $ty) -> $ret_ty {
     const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
     layout: intern_layout(LayoutS<VariantIdx>): Layout -> Layout<'tcx>,
     adt_def: intern_adt_def(AdtDefData): AdtDef -> AdtDef<'tcx>,
+    external_constraints: intern_external_constraints(ExternalConstraintsData<'tcx>): ExternalConstraints -> ExternalConstraints<'tcx>,
 }
 
 macro_rules! slice_interners {
index 4b4518f61e8d39b444bb4716a0ff13cf1966b54d..0a30ae9d0aa78522c461b8a6dff9c81d7e0b28e9 100644 (file)
@@ -3,8 +3,9 @@
 use std::ops::ControlFlow;
 
 use crate::ty::{
-    visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, InferConst, InferTy, Opaque,
-    PolyTraitPredicate, Projection, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
+    visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, FallibleTypeFolder, InferConst,
+    InferTy, Opaque, PolyTraitPredicate, Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
+    TypeSuperVisitable, TypeVisitor,
 };
 
 use rustc_data_structures::fx::FxHashMap;
@@ -76,7 +77,7 @@ pub fn is_simple_text(self) -> bool {
     }
 }
 
-pub trait IsSuggestable<'tcx> {
+pub trait IsSuggestable<'tcx>: Sized {
     /// Whether this makes sense to suggest in a diagnostic.
     ///
     /// We filter out certain types and constants since they don't provide
@@ -87,15 +88,21 @@ pub trait IsSuggestable<'tcx> {
     /// Only if `infer_suggestable` is true, we consider type and const
     /// inference variables to be suggestable.
     fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool;
+
+    fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<Self>;
 }
 
 impl<'tcx, T> IsSuggestable<'tcx> for T
 where
-    T: TypeVisitable<'tcx>,
+    T: TypeVisitable<'tcx> + TypeFoldable<'tcx>,
 {
     fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool {
         self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue()
     }
+
+    fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<T> {
+        self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable }).ok()
+    }
 }
 
 pub fn suggest_arbitrary_trait_bound<'tcx>(
@@ -186,6 +193,9 @@ fn suggest_removing_unsized_bound(
 }
 
 /// Suggest restricting a type param with a new bound.
+///
+/// If `span_to_replace` is provided, then that span will be replaced with the
+/// `constraint`. If one wasn't provided, then the full bound will be suggested.
 pub fn suggest_constraining_type_param(
     tcx: TyCtxt<'_>,
     generics: &hir::Generics<'_>,
@@ -193,12 +203,14 @@ pub fn suggest_constraining_type_param(
     param_name: &str,
     constraint: &str,
     def_id: Option<DefId>,
+    span_to_replace: Option<Span>,
 ) -> bool {
     suggest_constraining_type_params(
         tcx,
         generics,
         err,
         [(param_name, constraint, def_id)].into_iter(),
+        span_to_replace,
     )
 }
 
@@ -208,6 +220,7 @@ pub fn suggest_constraining_type_params<'a>(
     generics: &hir::Generics<'_>,
     err: &mut Diagnostic,
     param_names_and_constraints: impl Iterator<Item = (&'a str, &'a str, Option<DefId>)>,
+    span_to_replace: Option<Span>,
 ) -> bool {
     let mut grouped = FxHashMap::default();
     param_names_and_constraints.for_each(|(param_name, constraint, def_id)| {
@@ -246,7 +259,9 @@ pub fn suggest_constraining_type_params<'a>(
         let mut suggest_restrict = |span, bound_list_non_empty| {
             suggestions.push((
                 span,
-                if bound_list_non_empty {
+                if span_to_replace.is_some() {
+                    constraint.clone()
+                } else if bound_list_non_empty {
                     format!(" + {}", constraint)
                 } else {
                     format!(" {}", constraint)
@@ -255,6 +270,11 @@ pub fn suggest_constraining_type_params<'a>(
             ))
         };
 
+        if let Some(span) = span_to_replace {
+            suggest_restrict(span, true);
+            continue;
+        }
+
         // When the type parameter has been provided bounds
         //
         //    Message:
@@ -509,3 +529,83 @@ fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         c.super_visit_with(self)
     }
 }
+
+pub struct MakeSuggestableFolder<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    infer_suggestable: bool,
+}
+
+impl<'tcx> FallibleTypeFolder<'tcx> for MakeSuggestableFolder<'tcx> {
+    type Error = ();
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+        let t = match *t.kind() {
+            Infer(InferTy::TyVar(_)) if self.infer_suggestable => t,
+
+            FnDef(def_id, substs) => {
+                self.tcx.mk_fn_ptr(self.tcx.fn_sig(def_id).subst(self.tcx, substs))
+            }
+
+            // FIXME(compiler-errors): We could replace these with infer, I guess.
+            Closure(..)
+            | Infer(..)
+            | Generator(..)
+            | GeneratorWitness(..)
+            | Bound(_, _)
+            | Placeholder(_)
+            | Error(_) => {
+                return Err(());
+            }
+
+            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()
+                    && parent_opaque_def_id == def_id
+                {
+                    t
+                } else {
+                    return Err(());
+                }
+            }
+
+            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
+                // sufficient info to determine if it is synthetic, and we don't
+                // always have a convenient way of getting `ty::Generics` at the call
+                // sites we invoke `IsSuggestable::is_suggestable`.
+                if param.name.as_str().starts_with("impl ") {
+                    return Err(());
+                }
+
+                t
+            }
+
+            _ => t,
+        };
+
+        t.try_super_fold_with(self)
+    }
+
+    fn try_fold_const(&mut self, c: Const<'tcx>) -> Result<Const<'tcx>, ()> {
+        let c = match c.kind() {
+            ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => c,
+
+            ConstKind::Infer(..)
+            | ConstKind::Bound(..)
+            | ConstKind::Placeholder(..)
+            | ConstKind::Error(..) => {
+                return Err(());
+            }
+
+            _ => c,
+        };
+
+        c.try_super_fold_with(self)
+    }
+}
index 1445bc1ed32e60c604e275f948ce30722390a2b2..8a0019bc0127c9df4ee2e224d30567bf194d4992 100644 (file)
@@ -105,7 +105,7 @@ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
 /// the infallible methods of this trait to ensure that the two APIs
 /// are coherent.
 pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
+    fn tcx(&self) -> TyCtxt<'tcx>;
 
     fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
     where
index cdcd6281f209bb4d25761ebb9e0a6cd9d1fac8f3..4c2855821384bcf4ed35bda7e3635eaacdcc1e7d 100644 (file)
@@ -818,125 +818,114 @@ fn ty_and_layout_pointee_info_at(
         let tcx = cx.tcx();
         let param_env = cx.param_env();
 
-        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
-                                }
-                            }
-                        }
-                    };
+        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 => {
+                // 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).
+                let optimize = tcx.sess.opts.optimize != OptLevel::No;
+                let kind = match mt {
+                    hir::Mutability::Not => PointerKind::SharedRef {
+                        frozen: optimize && ty.is_freeze(tcx, cx.param_env()),
+                    },
+                    hir::Mutability::Mut => PointerKind::MutableRef {
+                        unpin: optimize && ty.is_unpin(tcx, cx.param_env()),
+                    },
+                };
 
-                    tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
-                        size: layout.size,
-                        align: layout.align.abi,
-                        safe: Some(kind),
-                    })
-                }
+                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 {
-                        // 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;
+                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;
                             }
                         }
                     }
+                }
 
-                    // 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 {
+                            let optimize = tcx.sess.opts.optimize != OptLevel::No;
+                            pointee.safe = Some(PointerKind::Box {
+                                unpin: optimize && this.ty.boxed_ty().is_unpin(tcx, cx.param_env()),
+                            });
                         }
                     }
-
-                    result
                 }
-            };
+
+                result
+            }
+        };
 
         debug!(
             "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
index 1be819ca610c7c644f7b3c9c9325f4c52bf81494..7151b79c5ab63f4b4b7ba8a56a4e5cd275320889 100644 (file)
@@ -106,16 +106,6 @@ pub fn try_mark_green(self, dep_node: &dep_graph::DepNode) -> bool {
     }
 }
 
-/// Helper for `TyCtxtEnsure` to avoid a closure.
-#[inline(always)]
-fn noop<T>(_: &T) {}
-
-/// Helper to ensure that queries only return `Copy` types.
-#[inline(always)]
-fn copy<T: Copy>(x: &T) -> T {
-    *x
-}
-
 macro_rules! query_helper_param_ty {
     (DefId) => { impl IntoQueryParam<DefId> };
     (LocalDefId) => { impl IntoQueryParam<LocalDefId> };
@@ -225,14 +215,10 @@ pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
                 let key = key.into_query_param();
                 opt_remap_env_constness!([$($modifiers)*][key]);
 
-                let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, noop);
-
-                match cached {
-                    Ok(()) => return,
-                    Err(()) => (),
-                }
-
-                self.tcx.queries.$name(self.tcx, DUMMY_SP, key, QueryMode::Ensure);
+                match try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key) {
+                    Some(_) => return,
+                    None => self.tcx.queries.$name(self.tcx, DUMMY_SP, key, QueryMode::Ensure),
+                };
             })*
         }
 
@@ -254,14 +240,10 @@ pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'
                 let key = key.into_query_param();
                 opt_remap_env_constness!([$($modifiers)*][key]);
 
-                let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, copy);
-
-                match cached {
-                    Ok(value) => return value,
-                    Err(()) => (),
+                match try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key) {
+                    Some(value) => value,
+                    None => self.tcx.queries.$name(self.tcx, self.span, key, QueryMode::Get).unwrap(),
                 }
-
-                self.tcx.queries.$name(self.tcx, self.span, key, QueryMode::Get).unwrap()
             })*
         }
 
@@ -353,27 +335,25 @@ pub fn $name(self, value: $V) -> query_stored::$name<'tcx> {
                 let tcx = self.tcx;
                 let cache = &tcx.query_caches.$name;
 
-                let cached = try_get_cached(tcx, cache, &key, copy);
-
-                match cached {
-                    Ok(old) => {
+                match try_get_cached(tcx, cache, &key) {
+                    Some(old) => {
                         bug!(
                             "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}",
                             stringify!($name),
+                        )
+                    }
+                    None => {
+                        let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::DepKind::$name, &key);
+                        let dep_node_index = tcx.dep_graph.with_feed_task(
+                            dep_node,
+                            tcx,
+                            key,
+                            &value,
+                            hash_result!([$($modifiers)*]),
                         );
+                        cache.complete(key, value, dep_node_index)
                     }
-                    Err(()) => (),
                 }
-
-                let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::DepKind::$name, &key);
-                let dep_node_index = tcx.dep_graph.with_feed_task(
-                    dep_node,
-                    tcx,
-                    key,
-                    &value,
-                    hash_result!([$($modifiers)*]),
-                );
-                cache.complete(key, value, dep_node_index)
             }
         })*
     }
index fa87301df7e779f09d0eb8f002164b7fe9e82221..890dabde1f73d4fe2967aec911a9f3ac469019a0 100644 (file)
@@ -629,6 +629,8 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
         b = tcx.expand_abstract_consts(b);
     }
 
+    debug!("{}.super_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b);
+
     // Currently, the values that can be unified are primitive types,
     // and those that derive both `PartialEq` and `Eq`, corresponding
     // to structural-match types.
@@ -665,30 +667,28 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
 
             // FIXME(generic_const_exprs): is it possible to relate two consts which are not identical
             // exprs? Should we care about that?
+            // FIXME(generic_const_exprs): relating the `ty()`s is a little weird since it is supposed to
+            // ICE If they mismatch. Unfortunately `ConstKind::Expr` is a little special and can be thought
+            // of as being generic over the argument types, however this is implicit so these types don't get
+            // related when we relate the substs of the item this const arg is for.
             let expr = match (ae, be) {
-                (Expr::Binop(a_op, al, ar), Expr::Binop(b_op, bl, br))
-                    if a_op == b_op && al.ty() == bl.ty() && ar.ty() == br.ty() =>
-                {
+                (Expr::Binop(a_op, al, ar), Expr::Binop(b_op, bl, br)) if a_op == b_op => {
+                    r.relate(al.ty(), bl.ty())?;
+                    r.relate(ar.ty(), br.ty())?;
                     Expr::Binop(a_op, r.consts(al, bl)?, r.consts(ar, br)?)
                 }
-                (Expr::UnOp(a_op, av), Expr::UnOp(b_op, bv))
-                    if a_op == b_op && av.ty() == bv.ty() =>
-                {
+                (Expr::UnOp(a_op, av), Expr::UnOp(b_op, bv)) if a_op == b_op => {
+                    r.relate(av.ty(), bv.ty())?;
                     Expr::UnOp(a_op, r.consts(av, bv)?)
                 }
-                (Expr::Cast(ak, av, at), Expr::Cast(bk, bv, bt))
-                    if ak == bk && av.ty() == bv.ty() =>
-                {
+                (Expr::Cast(ak, av, at), Expr::Cast(bk, bv, bt)) if ak == bk => {
+                    r.relate(av.ty(), bv.ty())?;
                     Expr::Cast(ak, r.consts(av, bv)?, r.tys(at, bt)?)
                 }
                 (Expr::FunctionCall(af, aa), Expr::FunctionCall(bf, ba))
-                    if aa.len() == ba.len()
-                        && af.ty() == bf.ty()
-                        && aa
-                            .iter()
-                            .zip(ba.iter())
-                            .all(|(a_arg, b_arg)| a_arg.ty() == b_arg.ty()) =>
+                    if aa.len() == ba.len() =>
                 {
+                    r.relate(af.ty(), bf.ty())?;
                     let func = r.consts(af, bf)?;
                     let mut related_args = Vec::with_capacity(aa.len());
                     for (a_arg, b_arg) in aa.iter().zip(ba.iter()) {
index 4ad3343d3031b2fa1e0f23eb2efc03ffd85edad1..f24b165d7c239345b13c7ac2647d89d6c20f10b7 100644 (file)
@@ -11,7 +11,6 @@ tracing = "0.1"
 either = "1"
 rustc_middle = { path = "../rustc_middle" }
 rustc_apfloat = { path = "../rustc_apfloat" }
-rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_index = { path = "../rustc_index" }
 rustc_errors = { path = "../rustc_errors" }
index c7b3eb44dc5fb52318b716a2d1c53ce3ae483b10..cd0e69328634b33e2b70785e6f13fd75b865240f 100644 (file)
@@ -439,10 +439,14 @@ pub(crate) fn as_rvalue(
                         // We implicitly set the discriminant to 0. See
                         // librustc_mir/transform/deaggregator.rs for details.
                         let movability = movability.unwrap();
-                        Box::new(AggregateKind::Generator(closure_id, substs, movability))
+                        Box::new(AggregateKind::Generator(
+                            closure_id.to_def_id(),
+                            substs,
+                            movability,
+                        ))
                     }
                     UpvarSubsts::Closure(substs) => {
-                        Box::new(AggregateKind::Closure(closure_id, substs))
+                        Box::new(AggregateKind::Closure(closure_id.to_def_id(), substs))
                     }
                 };
                 block.and(Rvalue::Aggregate(result, operands))
index 324644b67928edc3401cf2ff5a293d97e1cb366b..68c61a18d72fcde55c03c9e37ed6de8a8bd5c5d3 100644 (file)
@@ -19,6 +19,5 @@ rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_serialize = { path = "../rustc_serialize" }
-rustc_session = { path = "../rustc_session" }
 rustc_target = { path = "../rustc_target" }
 rustc_span = { path = "../rustc_span" }
index 6bdbda909d7bdf02da963730db84fa2a3d2be991..8bf6493be4b0168ba6e78d8be9d0cbb7c038382c 100644 (file)
@@ -790,7 +790,7 @@ fn try_from(value: ProjectionElem<V, T>) -> Result<Self, Self::Error> {
 }
 
 /// Invokes `f` on all direct fields of `ty`.
-fn iter_fields<'tcx>(
+pub fn iter_fields<'tcx>(
     ty: Ty<'tcx>,
     tcx: TyCtxt<'tcx>,
     mut f: impl FnMut(Option<VariantIdx>, Field, Ty<'tcx>),
@@ -824,7 +824,7 @@ fn iter_fields<'tcx>(
 }
 
 /// Returns all locals with projections that have their reference or address taken.
-fn excluded_locals(body: &Body<'_>) -> IndexVec<Local, bool> {
+pub fn excluded_locals(body: &Body<'_>) -> IndexVec<Local, bool> {
     struct Collector {
         result: IndexVec<Local, bool>,
     }
index 8afa53313fc2840e838cc13e8d5d4170a3151de3..d00ee1f4babe8b3aed8b835ab633fca0db04c2e0 100644 (file)
@@ -126,6 +126,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                     }
                 }
                 &AggregateKind::Closure(def_id, _) | &AggregateKind::Generator(def_id, _, _) => {
+                    let def_id = def_id.expect_local();
                     let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
                         self.tcx.unsafety_check_result(def_id);
                     self.register_violations(violations, used_unsafe_blocks.iter().copied());
index 4c7d45be0753e1944d25e60434463fb964a462b2..6e279232bcb48ce3e22ed586e0d9b6c96ec6dde9 100644 (file)
@@ -153,8 +153,9 @@ fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Loca
 
     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)
+            // A move out of a projection of a copy is equivalent to a copy of the original projection.
+            && !place.has_deref()
+            && !self.fully_moved.contains(place.local)
         {
             *operand = Operand::Copy(place);
         }
index c75fe2327de3eb0b52e35f0cbebfe02fc9282838..949a59a97bfb6a6e56b75d88d31f84c092530b61 100644 (file)
@@ -5,6 +5,7 @@
 use rustc_const_eval::const_eval::CheckAlignment;
 use rustc_const_eval::interpret::{ConstValue, ImmTy, Immediate, InterpCx, Scalar};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def::DefKind;
 use rustc_middle::mir::visit::{MutVisitor, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -85,6 +86,30 @@ fn handle_assign(
         state: &mut State<Self::Value>,
     ) {
         match rvalue {
+            Rvalue::Aggregate(kind, operands) => {
+                let target = self.map().find(target.as_ref());
+                if let Some(target) = target {
+                    state.flood_idx_with(target, self.map(), FlatSet::Bottom);
+                    let field_based = match **kind {
+                        AggregateKind::Tuple | AggregateKind::Closure(..) => true,
+                        AggregateKind::Adt(def_id, ..) => {
+                            matches!(self.tcx.def_kind(def_id), DefKind::Struct)
+                        }
+                        _ => false,
+                    };
+                    if field_based {
+                        for (field_index, operand) in operands.iter().enumerate() {
+                            if let Some(field) = self
+                                .map()
+                                .apply(target, TrackElem::Field(Field::from_usize(field_index)))
+                            {
+                                let result = self.handle_operand(operand, state);
+                                state.assign_idx(field, result, self.map());
+                            }
+                        }
+                    }
+                }
+            }
             Rvalue::CheckedBinaryOp(op, box (left, right)) => {
                 let target = self.map().find(target.as_ref());
                 if let Some(target) = target {
diff --git a/compiler/rustc_mir_transform/src/deaggregator.rs b/compiler/rustc_mir_transform/src/deaggregator.rs
deleted file mode 100644 (file)
index fe272de..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-use crate::util::expand_aggregate;
-use crate::MirPass;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-
-pub struct Deaggregator;
-
-impl<'tcx> MirPass<'tcx> for Deaggregator {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
-        for bb in basic_blocks {
-            bb.expand_statements(|stmt| {
-                // FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL).
-                match stmt.kind {
-                    // FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
-                    StatementKind::Assign(box (
-                        _,
-                        Rvalue::Aggregate(box AggregateKind::Array(_), _),
-                    )) => {
-                        return None;
-                    }
-                    StatementKind::Assign(box (_, Rvalue::Aggregate(_, _))) => {}
-                    _ => return None,
-                }
-
-                let stmt = stmt.replace_nop();
-                let source_info = stmt.source_info;
-                let StatementKind::Assign(box (lhs, Rvalue::Aggregate(kind, operands))) = stmt.kind else {
-                    bug!();
-                };
-
-                Some(expand_aggregate(
-                    lhs,
-                    operands.into_iter().map(|op| {
-                        let ty = op.ty(&body.local_decls, tcx);
-                        (op, ty)
-                    }),
-                    *kind,
-                    source_info,
-                    tcx,
-                ))
-            });
-        }
-    }
-}
index 5624e312da1cbe8eeabe9cbc82d219ebea390f86..47f9d35a4f7ec5e7101fadb5bb3a04a0721d2aea 100644 (file)
@@ -52,7 +52,6 @@
 
 use crate::deref_separator::deref_finder;
 use crate::simplify;
-use crate::util::expand_aggregate;
 use crate::MirPass;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::pluralize;
@@ -272,31 +271,26 @@ fn make_state(
             assert_eq!(self.state_adt_ref.variant(idx).fields.len(), 0);
 
             // FIXME(swatinem): assert that `val` is indeed unit?
-            statements.extend(expand_aggregate(
-                Place::return_place(),
-                std::iter::empty(),
-                kind,
+            statements.push(Statement {
+                kind: StatementKind::Assign(Box::new((
+                    Place::return_place(),
+                    Rvalue::Aggregate(Box::new(kind), vec![]),
+                ))),
                 source_info,
-                self.tcx,
-            ));
+            });
             return;
         }
 
         // else: `Poll::Ready(x)`, `GeneratorState::Yielded(x)` or `GeneratorState::Complete(x)`
         assert_eq!(self.state_adt_ref.variant(idx).fields.len(), 1);
 
-        let ty = self
-            .tcx
-            .bound_type_of(self.state_adt_ref.variant(idx).fields[0].did)
-            .subst(self.tcx, self.state_substs);
-
-        statements.extend(expand_aggregate(
-            Place::return_place(),
-            std::iter::once((val, ty)),
-            kind,
+        statements.push(Statement {
+            kind: StatementKind::Assign(Box::new((
+                Place::return_place(),
+                Rvalue::Aggregate(Box::new(kind), vec![val]),
+            ))),
             source_info,
-            self.tcx,
-        ));
+        });
     }
 
     // Create a Place referencing a generator struct field
index 6815289776e9372059aecd2df65d93a4d7525efa..9070a7368b168049c6bae014116324261b1d490e 100644 (file)
@@ -60,7 +60,6 @@
 mod ctfe_limit;
 mod dataflow_const_prop;
 mod dead_store_elimination;
-mod deaggregator;
 mod deduce_param_attrs;
 mod deduplicate_blocks;
 mod deref_separator;
@@ -523,9 +522,6 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         &elaborate_box_derefs::ElaborateBoxDerefs,
         &generator::StateTransform,
         &add_retag::AddRetag,
-        // Deaggregator is necessary for const prop. We may want to consider implementing
-        // CTFE support for aggregates.
-        &deaggregator::Deaggregator,
         &Lint(const_prop_lint::ConstProp),
     ];
     pm::run_passes_no_validate(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::Initial)));
index e9ca6f7c93c446b569f72aa608087182c874b734..551422386f6e012aaa28ed75abcb76f210f38713 100644 (file)
@@ -15,7 +15,6 @@
 use std::fmt;
 use std::iter;
 
-use crate::util::expand_aggregate;
 use crate::{
     abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator,
     pass_manager as pm, remove_noop_landing_pads, simplify,
@@ -831,19 +830,23 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
     // return;
     debug!("build_ctor: variant_index={:?}", variant_index);
 
-    let statements = expand_aggregate(
-        Place::return_place(),
-        adt_def.variant(variant_index).fields.iter().enumerate().map(|(idx, field_def)| {
-            (Operand::Move(Place::from(Local::new(idx + 1))), field_def.ty(tcx, substs))
-        }),
-        AggregateKind::Adt(adt_def.did(), variant_index, substs, None, None),
+    let kind = AggregateKind::Adt(adt_def.did(), variant_index, substs, None, None);
+    let variant = adt_def.variant(variant_index);
+    let statement = Statement {
+        kind: StatementKind::Assign(Box::new((
+            Place::return_place(),
+            Rvalue::Aggregate(
+                Box::new(kind),
+                (0..variant.fields.len())
+                    .map(|idx| Operand::Move(Place::from(Local::new(idx + 1))))
+                    .collect(),
+            ),
+        ))),
         source_info,
-        tcx,
-    )
-    .collect();
+    };
 
     let start_block = BasicBlockData {
-        statements,
+        statements: vec![statement],
         terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
         is_cleanup: false,
     };
index 42124f5a4808d0a3ff074da042b6db40791be5e1..26acd406ed8a9f81616240e55d6b533d680ed79c 100644 (file)
@@ -1,10 +1,11 @@
 use crate::MirPass;
-use rustc_data_structures::fx::{FxIndexMap, IndexEntry};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
+use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_mir_dataflow::value_analysis::{excluded_locals, iter_fields};
 
 pub struct ScalarReplacementOfAggregates;
 
@@ -13,27 +14,41 @@ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() >= 3
     }
 
+    #[instrument(level = "debug", skip(self, tcx, body))]
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let escaping = escaping_locals(&*body);
-        debug!(?escaping);
-        let replacements = compute_flattening(tcx, body, escaping);
-        debug!(?replacements);
-        replace_flattened_locals(tcx, body, replacements);
+        debug!(def_id = ?body.source.def_id());
+        let mut excluded = excluded_locals(body);
+        loop {
+            debug!(?excluded);
+            let escaping = escaping_locals(&excluded, body);
+            debug!(?escaping);
+            let replacements = compute_flattening(tcx, body, escaping);
+            debug!(?replacements);
+            let all_dead_locals = replace_flattened_locals(tcx, body, replacements);
+            if !all_dead_locals.is_empty() {
+                for local in excluded.indices() {
+                    excluded[local] |= all_dead_locals.contains(local);
+                }
+                excluded.raw.resize(body.local_decls.len(), false);
+            } else {
+                break;
+            }
+        }
     }
 }
 
 /// Identify all locals that are not eligible for SROA.
 ///
 /// There are 3 cases:
-/// - the aggegated local is used or passed to other code (function parameters and arguments);
+/// - the aggregated local is used or passed to other code (function parameters and arguments);
 /// - the locals is a union or an enum;
 /// - the local's address is taken, and thus the relative addresses of the fields are observable to
 ///   client code.
-fn escaping_locals(body: &Body<'_>) -> BitSet<Local> {
+fn escaping_locals(excluded: &IndexVec<Local, bool>, body: &Body<'_>) -> BitSet<Local> {
     let mut set = BitSet::new_empty(body.local_decls.len());
     set.insert_range(RETURN_PLACE..=Local::from_usize(body.arg_count));
     for (local, decl) in body.local_decls().iter_enumerated() {
-        if decl.ty.is_union() || decl.ty.is_enum() {
+        if decl.ty.is_union() || decl.ty.is_enum() || excluded[local] {
             set.insert(local);
         }
     }
@@ -58,41 +73,33 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location:
             self.super_place(place, context, location);
         }
 
-        fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
-            if let Rvalue::AddressOf(.., place) | Rvalue::Ref(.., place) = rvalue {
-                if !place.is_indirect() {
-                    // Raw pointers may be used to access anything inside the enclosing place.
-                    self.set.insert(place.local);
-                    return;
+        fn visit_assign(
+            &mut self,
+            lvalue: &Place<'tcx>,
+            rvalue: &Rvalue<'tcx>,
+            location: Location,
+        ) {
+            if lvalue.as_local().is_some() {
+                match rvalue {
+                    // Aggregate assignments are expanded in run_pass.
+                    Rvalue::Aggregate(..) | Rvalue::Use(..) => {
+                        self.visit_rvalue(rvalue, location);
+                        return;
+                    }
+                    _ => {}
                 }
             }
-            self.super_rvalue(rvalue, location)
+            self.super_assign(lvalue, rvalue, location)
         }
 
         fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
-            if let StatementKind::StorageLive(..)
-            | StatementKind::StorageDead(..)
-            | StatementKind::Deinit(..) = statement.kind
-            {
+            match statement.kind {
                 // Storage statements are expanded in run_pass.
-                return;
+                StatementKind::StorageLive(..)
+                | StatementKind::StorageDead(..)
+                | StatementKind::Deinit(..) => return,
+                _ => self.super_statement(statement, location),
             }
-            self.super_statement(statement, location)
-        }
-
-        fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-            // Drop implicitly calls `drop_in_place`, which takes a `&mut`.
-            // This implies that `Drop` implicitly takes the address of the place.
-            if let TerminatorKind::Drop { place, .. }
-            | TerminatorKind::DropAndReplace { place, .. } = terminator.kind
-            {
-                if !place.is_indirect() {
-                    // Raw pointers may be used to access anything inside the enclosing place.
-                    self.set.insert(place.local);
-                    return;
-                }
-            }
-            self.super_terminator(terminator, location);
         }
 
         // We ignore anything that happens in debuginfo, since we expand it using
@@ -103,7 +110,30 @@ fn visit_var_debug_info(&mut self, _: &VarDebugInfo<'tcx>) {}
 
 #[derive(Default, Debug)]
 struct ReplacementMap<'tcx> {
-    fields: FxIndexMap<PlaceRef<'tcx>, Local>,
+    /// 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, Option<IndexVec<Field, Option<(Ty<'tcx>, Local)>>>>,
+}
+
+impl<'tcx> ReplacementMap<'tcx> {
+    fn replace_place(&self, tcx: TyCtxt<'tcx>, place: PlaceRef<'tcx>) -> Option<Place<'tcx>> {
+        let &[PlaceElem::Field(f, _), ref rest @ ..] = place.projection else { return None; };
+        let fields = self.fragments[place.local].as_ref()?;
+        let (_, new_local) = fields[f]?;
+        Some(Place { local: new_local, projection: tcx.intern_place_elems(&rest) })
+    }
+
+    fn place_fragments(
+        &self,
+        place: Place<'tcx>,
+    ) -> Option<impl Iterator<Item = (Field, Ty<'tcx>, Local)> + '_> {
+        let local = place.as_local()?;
+        let fields = self.fragments[local].as_ref()?;
+        Some(fields.iter_enumerated().filter_map(|(field, &opt_ty_local)| {
+            let (ty, local) = opt_ty_local?;
+            Some((field, ty, local))
+        }))
+    }
 }
 
 /// Compute the replacement of flattened places into locals.
@@ -115,53 +145,25 @@ fn compute_flattening<'tcx>(
     body: &mut Body<'tcx>,
     escaping: BitSet<Local>,
 ) -> ReplacementMap<'tcx> {
-    let mut visitor = PreFlattenVisitor {
-        tcx,
-        escaping,
-        local_decls: &mut body.local_decls,
-        map: Default::default(),
-    };
-    for (block, bbdata) in body.basic_blocks.iter_enumerated() {
-        visitor.visit_basic_block_data(block, bbdata);
-    }
-    return visitor.map;
-
-    struct PreFlattenVisitor<'tcx, 'll> {
-        tcx: TyCtxt<'tcx>,
-        local_decls: &'ll mut LocalDecls<'tcx>,
-        escaping: BitSet<Local>,
-        map: ReplacementMap<'tcx>,
-    }
-
-    impl<'tcx, 'll> PreFlattenVisitor<'tcx, 'll> {
-        fn create_place(&mut self, place: PlaceRef<'tcx>) {
-            if self.escaping.contains(place.local) {
-                return;
-            }
+    let mut fragments = IndexVec::from_elem(None, &body.local_decls);
 
-            match self.map.fields.entry(place) {
-                IndexEntry::Occupied(_) => {}
-                IndexEntry::Vacant(v) => {
-                    let ty = place.ty(&*self.local_decls, self.tcx).ty;
-                    let local = self.local_decls.push(LocalDecl {
-                        ty,
-                        user_ty: None,
-                        ..self.local_decls[place.local].clone()
-                    });
-                    v.insert(local);
-                }
-            }
-        }
-    }
-
-    impl<'tcx, 'll> Visitor<'tcx> for PreFlattenVisitor<'tcx, 'll> {
-        fn visit_place(&mut self, place: &Place<'tcx>, _: PlaceContext, _: Location) {
-            if let &[PlaceElem::Field(..), ..] = &place.projection[..] {
-                let pr = PlaceRef { local: place.local, projection: &place.projection[..1] };
-                self.create_place(pr)
-            }
+    for local in body.local_decls.indices() {
+        if escaping.contains(local) {
+            continue;
         }
+        let decl = body.local_decls[local].clone();
+        let ty = decl.ty;
+        iter_fields(ty, tcx, |variant, field, field_ty| {
+            if variant.is_some() {
+                // Downcasts are currently not supported.
+                return;
+            };
+            let new_local =
+                body.local_decls.push(LocalDecl { ty: field_ty, user_ty: None, ..decl.clone() });
+            fragments.get_or_insert_with(local, IndexVec::new).insert(field, (field_ty, new_local));
+        });
     }
+    ReplacementMap { fragments }
 }
 
 /// Perform the replacement computed by `compute_flattening`.
@@ -169,29 +171,24 @@ fn replace_flattened_locals<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &mut Body<'tcx>,
     replacements: ReplacementMap<'tcx>,
-) {
+) -> BitSet<Local> {
     let mut all_dead_locals = BitSet::new_empty(body.local_decls.len());
-    for p in replacements.fields.keys() {
-        all_dead_locals.insert(p.local);
+    for (local, replacements) in replacements.fragments.iter_enumerated() {
+        if replacements.is_some() {
+            all_dead_locals.insert(local);
+        }
     }
     debug!(?all_dead_locals);
     if all_dead_locals.is_empty() {
-        return;
+        return all_dead_locals;
     }
 
-    let mut fragments = IndexVec::new();
-    for (k, v) in &replacements.fields {
-        fragments.ensure_contains_elem(k.local, || Vec::new());
-        fragments[k.local].push((k.projection, *v));
-    }
-    debug!(?fragments);
-
     let mut visitor = ReplacementVisitor {
         tcx,
         local_decls: &body.local_decls,
-        replacements,
+        replacements: &replacements,
         all_dead_locals,
-        fragments,
+        patch: MirPatch::new(body),
     };
     for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
         visitor.visit_basic_block_data(bb, data);
@@ -205,6 +202,9 @@ fn replace_flattened_locals<'tcx>(
     for var_debug_info in &mut body.var_debug_info {
         visitor.visit_var_debug_info(var_debug_info);
     }
+    let ReplacementVisitor { patch, all_dead_locals, .. } = visitor;
+    patch.apply(body);
+    all_dead_locals
 }
 
 struct ReplacementVisitor<'tcx, 'll> {
@@ -212,40 +212,23 @@ struct ReplacementVisitor<'tcx, 'll> {
     /// This is only used to compute the type for `VarDebugInfoContents::Composite`.
     local_decls: &'ll LocalDecls<'tcx>,
     /// Work to do.
-    replacements: ReplacementMap<'tcx>,
+    replacements: &'ll 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
-    /// and deinit statement and debuginfo.
-    fragments: IndexVec<Local, Vec<(&'tcx [PlaceElem<'tcx>], Local)>>,
+    patch: MirPatch<'tcx>,
 }
 
-impl<'tcx, 'll> ReplacementVisitor<'tcx, 'll> {
-    fn gather_debug_info_fragments(
-        &self,
-        place: PlaceRef<'tcx>,
-    ) -> Vec<VarDebugInfoFragment<'tcx>> {
+impl<'tcx> ReplacementVisitor<'tcx, '_> {
+    fn gather_debug_info_fragments(&self, local: Local) -> Option<Vec<VarDebugInfoFragment<'tcx>>> {
         let mut fragments = Vec::new();
-        let parts = &self.fragments[place.local];
-        for (proj, replacement_local) in parts {
-            if proj.starts_with(place.projection) {
-                fragments.push(VarDebugInfoFragment {
-                    projection: proj[place.projection.len()..].to_vec(),
-                    contents: Place::from(*replacement_local),
-                });
-            }
-        }
-        fragments
-    }
-
-    fn replace_place(&self, place: PlaceRef<'tcx>) -> Option<Place<'tcx>> {
-        if let &[PlaceElem::Field(..), ref rest @ ..] = place.projection {
-            let pr = PlaceRef { local: place.local, projection: &place.projection[..1] };
-            let local = self.replacements.fields.get(&pr)?;
-            Some(Place { local: *local, projection: self.tcx.intern_place_elems(&rest) })
-        } else {
-            None
+        let parts = self.replacements.place_fragments(local.into())?;
+        for (field, ty, replacement_local) in parts {
+            fragments.push(VarDebugInfoFragment {
+                projection: vec![PlaceElem::Field(field, ty)],
+                contents: Place::from(replacement_local),
+            });
         }
+        Some(fragments)
     }
 }
 
@@ -254,94 +237,186 @@ fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
-    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
-        if let StatementKind::StorageLive(..)
-        | StatementKind::StorageDead(..)
-        | StatementKind::Deinit(..) = statement.kind
-        {
-            // Storage statements are expanded in run_pass.
-            return;
-        }
-        self.super_statement(statement, location)
-    }
-
     fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        if let Some(repl) = self.replace_place(place.as_ref()) {
+        if let Some(repl) = self.replacements.replace_place(self.tcx, place.as_ref()) {
             *place = repl
         } else {
             self.super_place(place, context, location)
         }
     }
 
+    #[instrument(level = "trace", skip(self))]
+    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
+        match statement.kind {
+            // Duplicate storage and deinit statements, as they pretty much apply to all fields.
+            StatementKind::StorageLive(l) => {
+                if let Some(final_locals) = self.replacements.place_fragments(l.into()) {
+                    for (_, _, fl) in final_locals {
+                        self.patch.add_statement(location, StatementKind::StorageLive(fl));
+                    }
+                    statement.make_nop();
+                }
+                return;
+            }
+            StatementKind::StorageDead(l) => {
+                if let Some(final_locals) = self.replacements.place_fragments(l.into()) {
+                    for (_, _, fl) in final_locals {
+                        self.patch.add_statement(location, StatementKind::StorageDead(fl));
+                    }
+                    statement.make_nop();
+                }
+                return;
+            }
+            StatementKind::Deinit(box place) => {
+                if let Some(final_locals) = self.replacements.place_fragments(place) {
+                    for (_, _, fl) in final_locals {
+                        self.patch
+                            .add_statement(location, StatementKind::Deinit(Box::new(fl.into())));
+                    }
+                    statement.make_nop();
+                    return;
+                }
+            }
+
+            // We have `a = Struct { 0: x, 1: y, .. }`.
+            // We replace it by
+            // ```
+            // a_0 = x
+            // a_1 = y
+            // ...
+            // ```
+            StatementKind::Assign(box (place, Rvalue::Aggregate(_, ref mut operands))) => {
+                if let Some(local) = place.as_local()
+                    && let Some(final_locals) = &self.replacements.fragments[local]
+                {
+                    // This is ok as we delete the statement later.
+                    let operands = std::mem::take(operands);
+                    for (&opt_ty_local, mut operand) in final_locals.iter().zip(operands) {
+                        if let Some((_, new_local)) = opt_ty_local {
+                            // Replace mentions of SROA'd locals that appear in the operand.
+                            self.visit_operand(&mut operand, location);
+
+                            let rvalue = Rvalue::Use(operand);
+                            self.patch.add_statement(
+                                location,
+                                StatementKind::Assign(Box::new((new_local.into(), rvalue))),
+                            );
+                        }
+                    }
+                    statement.make_nop();
+                    return;
+                }
+            }
+
+            // We have `a = some constant`
+            // We add the projections.
+            // ```
+            // a_0 = a.0
+            // a_1 = a.1
+            // ...
+            // ```
+            // ConstProp will pick up the pieces and replace them by actual constants.
+            StatementKind::Assign(box (place, Rvalue::Use(Operand::Constant(_)))) => {
+                if let Some(final_locals) = self.replacements.place_fragments(place) {
+                    for (field, ty, new_local) in final_locals {
+                        let rplace = self.tcx.mk_place_field(place, field, ty);
+                        let rvalue = Rvalue::Use(Operand::Move(rplace));
+                        self.patch.add_statement(
+                            location,
+                            StatementKind::Assign(Box::new((new_local.into(), rvalue))),
+                        );
+                    }
+                    // We still need `place.local` to exist, so don't make it nop.
+                    return;
+                }
+            }
+
+            // We have `a = move? place`
+            // We replace it by
+            // ```
+            // a_0 = move? place.0
+            // a_1 = move? place.1
+            // ...
+            // ```
+            StatementKind::Assign(box (lhs, Rvalue::Use(ref op))) => {
+                let (rplace, copy) = match *op {
+                    Operand::Copy(rplace) => (rplace, true),
+                    Operand::Move(rplace) => (rplace, false),
+                    Operand::Constant(_) => bug!(),
+                };
+                if let Some(final_locals) = self.replacements.place_fragments(lhs) {
+                    for (field, ty, new_local) in final_locals {
+                        let rplace = self.tcx.mk_place_field(rplace, field, ty);
+                        debug!(?rplace);
+                        let rplace = self
+                            .replacements
+                            .replace_place(self.tcx, rplace.as_ref())
+                            .unwrap_or(rplace);
+                        debug!(?rplace);
+                        let rvalue = if copy {
+                            Rvalue::Use(Operand::Copy(rplace))
+                        } else {
+                            Rvalue::Use(Operand::Move(rplace))
+                        };
+                        self.patch.add_statement(
+                            location,
+                            StatementKind::Assign(Box::new((new_local.into(), rvalue))),
+                        );
+                    }
+                    statement.make_nop();
+                    return;
+                }
+            }
+
+            _ => {}
+        }
+        self.super_statement(statement, location)
+    }
+
+    #[instrument(level = "trace", skip(self))]
     fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) {
         match &mut var_debug_info.value {
             VarDebugInfoContents::Place(ref mut place) => {
-                if let Some(repl) = self.replace_place(place.as_ref()) {
+                if let Some(repl) = self.replacements.replace_place(self.tcx, place.as_ref()) {
                     *place = repl;
-                } else if self.all_dead_locals.contains(place.local) {
+                } else if let Some(local) = place.as_local()
+                    && let Some(fragments) = self.gather_debug_info_fragments(local)
+                {
                     let ty = place.ty(self.local_decls, self.tcx).ty;
-                    let fragments = self.gather_debug_info_fragments(place.as_ref());
                     var_debug_info.value = VarDebugInfoContents::Composite { ty, fragments };
                 }
             }
             VarDebugInfoContents::Composite { ty: _, ref mut fragments } => {
                 let mut new_fragments = Vec::new();
+                debug!(?fragments);
                 fragments
                     .drain_filter(|fragment| {
-                        if let Some(repl) = self.replace_place(fragment.contents.as_ref()) {
+                        if let Some(repl) =
+                            self.replacements.replace_place(self.tcx, fragment.contents.as_ref())
+                        {
                             fragment.contents = repl;
-                            true
-                        } else if self.all_dead_locals.contains(fragment.contents.local) {
-                            let frg = self.gather_debug_info_fragments(fragment.contents.as_ref());
+                            false
+                        } else if let Some(local) = fragment.contents.as_local()
+                            && let Some(frg) = self.gather_debug_info_fragments(local)
+                        {
                             new_fragments.extend(frg.into_iter().map(|mut f| {
                                 f.projection.splice(0..0, fragment.projection.iter().copied());
                                 f
                             }));
-                            false
-                        } else {
                             true
+                        } else {
+                            false
                         }
                     })
                     .for_each(drop);
+                debug!(?fragments);
+                debug!(?new_fragments);
                 fragments.extend(new_fragments);
             }
             VarDebugInfoContents::Const(_) => {}
         }
     }
 
-    fn visit_basic_block_data(&mut self, bb: BasicBlock, bbdata: &mut BasicBlockData<'tcx>) {
-        self.super_basic_block_data(bb, bbdata);
-
-        #[derive(Debug)]
-        enum Stmt {
-            StorageLive,
-            StorageDead,
-            Deinit,
-        }
-
-        bbdata.expand_statements(|stmt| {
-            let source_info = stmt.source_info;
-            let (stmt, origin_local) = match &stmt.kind {
-                StatementKind::StorageLive(l) => (Stmt::StorageLive, *l),
-                StatementKind::StorageDead(l) => (Stmt::StorageDead, *l),
-                StatementKind::Deinit(p) if let Some(l) = p.as_local() => (Stmt::Deinit, l),
-                _ => return None,
-            };
-            if !self.all_dead_locals.contains(origin_local) {
-                return None;
-            }
-            let final_locals = self.fragments.get(origin_local)?;
-            Some(final_locals.iter().map(move |&(_, l)| {
-                let kind = match stmt {
-                    Stmt::StorageLive => StatementKind::StorageLive(l),
-                    Stmt::StorageDead => StatementKind::StorageDead(l),
-                    Stmt::Deinit => StatementKind::Deinit(Box::new(l.into())),
-                };
-                Statement { source_info, kind }
-            }))
-        });
-    }
-
     fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
         assert!(!self.all_dead_locals.contains(*local));
     }
index fd4333dbbecc3763f3dace3162c65890403af1cc..0c11e0026900e4c2f5b5c6abb931ca3a460f8cc4 100644 (file)
@@ -433,6 +433,18 @@ pub(crate) enum MissingInInForLoopSub {
     AddIn(#[primary_span] Span),
 }
 
+#[derive(Diagnostic)]
+#[diag(parse_missing_expression_in_for_loop)]
+pub(crate) struct MissingExpressionInForLoop {
+    #[primary_span]
+    #[suggestion(
+        code = "/* expression */ ",
+        applicability = "has-placeholders",
+        style = "verbose"
+    )]
+    pub span: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(parse_missing_comma_after_match_arm)]
 pub(crate) struct MissingCommaAfterMatchArm {
@@ -1589,6 +1601,14 @@ pub(crate) struct UnexpectedSelfInGenericParameters {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(parse_unexpected_default_value_for_lifetime_in_generic_parameters)]
+pub(crate) struct UnexpectedDefaultValueForLifetimeInGenericParameters {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(parse_multiple_where_clauses)]
 pub(crate) struct MultipleWhereClauses {
index 8a6436b041b90c717b5eaa2d4a2abd055a2e1c6a..c37808f8c3d19b244e01abe806ef5f50e59ccba9 100644 (file)
@@ -5,26 +5,7 @@
     AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
     SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken,
 };
-use crate::errors::{
-    ArrayBracketsInsteadOfSpaces, ArrayBracketsInsteadOfSpacesSugg, AsyncBlockIn2015,
-    AsyncMoveOrderIncorrect, BracesForStructLiteral, CatchAfterTry, CommaAfterBaseStruct,
-    ComparisonInterpretedAsGeneric, ComparisonOrShiftInterpretedAsGenericSugg,
-    DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, ExpectedElseBlock, ExpectedEqForLetExpr,
-    ExpectedExpressionFoundLet, FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart,
-    FoundExprWouldBeStmt, HelpUseLatestEdition, 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,
-};
+use crate::errors;
 use crate::maybe_recover_from_interpolated_ty_qpath;
 use core::mem;
 use rustc_ast::ptr::P;
@@ -244,10 +225,10 @@ pub(super) fn parse_assoc_expr_with(
                 }
                 .into();
                 let invalid = format!("{}=", &sugg);
-                self.sess.emit_err(InvalidComparisonOperator {
+                self.sess.emit_err(errors::InvalidComparisonOperator {
                     span: sp,
                     invalid: invalid.clone(),
-                    sub: InvalidComparisonOperatorSub::Correctable {
+                    sub: errors::InvalidComparisonOperatorSub::Correctable {
                         span: sp,
                         invalid,
                         correct: sugg,
@@ -262,10 +243,10 @@ pub(super) fn parse_assoc_expr_with(
                 && self.prev_token.span.hi() == self.token.span.lo()
             {
                 let sp = op.span.to(self.token.span);
-                self.sess.emit_err(InvalidComparisonOperator {
+                self.sess.emit_err(errors::InvalidComparisonOperator {
                     span: sp,
                     invalid: "<>".into(),
-                    sub: InvalidComparisonOperatorSub::Correctable {
+                    sub: errors::InvalidComparisonOperatorSub::Correctable {
                         span: sp,
                         invalid: "<>".into(),
                         correct: "!=".into(),
@@ -280,10 +261,10 @@ pub(super) fn parse_assoc_expr_with(
                 && self.prev_token.span.hi() == self.token.span.lo()
             {
                 let sp = op.span.to(self.token.span);
-                self.sess.emit_err(InvalidComparisonOperator {
+                self.sess.emit_err(errors::InvalidComparisonOperator {
                     span: sp,
                     invalid: "<=>".into(),
-                    sub: InvalidComparisonOperatorSub::Spaceship(sp),
+                    sub: errors::InvalidComparisonOperatorSub::Spaceship(sp),
                 });
                 self.bump();
             }
@@ -420,7 +401,7 @@ fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
     /// but the next token implies this should be parsed as an expression.
     /// For example: `if let Some(x) = x { x } else { 0 } / 2`.
     fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {
-        self.sess.emit_err(FoundExprWouldBeStmt {
+        self.sess.emit_err(errors::FoundExprWouldBeStmt {
             span: self.token.span,
             token: self.token.clone(),
             suggestion: ExprParenthesesNeeded::surrounding(lhs.span),
@@ -447,18 +428,18 @@ fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
             }
             (Some(op), _) => (op, self.token.span),
             (None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => {
-                self.sess.emit_err(InvalidLogicalOperator {
+                self.sess.emit_err(errors::InvalidLogicalOperator {
                     span: self.token.span,
                     incorrect: "and".into(),
-                    sub: InvalidLogicalOperatorSub::Conjunction(self.token.span),
+                    sub: errors::InvalidLogicalOperatorSub::Conjunction(self.token.span),
                 });
                 (AssocOp::LAnd, span)
             }
             (None, Some((Ident { name: sym::or, span }, false))) if self.may_recover() => {
-                self.sess.emit_err(InvalidLogicalOperator {
+                self.sess.emit_err(errors::InvalidLogicalOperator {
                     span: self.token.span,
                     incorrect: "or".into(),
-                    sub: InvalidLogicalOperatorSub::Disjunction(self.token.span),
+                    sub: errors::InvalidLogicalOperatorSub::Disjunction(self.token.span),
                 });
                 (AssocOp::LOr, span)
             }
@@ -581,8 +562,11 @@ macro_rules! make_it {
             }
             // `+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 };
+                let mut err = errors::LeadingPlusNotSupported {
+                    span: lo,
+                    remove_plus: None,
+                    add_parentheses: None,
+                };
 
                 // a block on the LHS might have been intended to be an expression instead
                 if let Some(sp) = this.sess.ambiguous_block_expr_parse.borrow().get(&lo) {
@@ -633,7 +617,7 @@ fn parse_unary_expr(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKin
 
     /// 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));
+        self.sess.emit_err(errors::TildeAsUnaryOperator(lo));
 
         self.parse_unary_expr(lo, UnOp::Not)
     }
@@ -661,14 +645,14 @@ fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
         let negated_token = self.look_ahead(1, |t| t.clone());
 
         let sub_diag = if negated_token.is_numeric_lit() {
-            NotAsNegationOperatorSub::SuggestNotBitwise
+            errors::NotAsNegationOperatorSub::SuggestNotBitwise
         } else if negated_token.is_bool_lit() {
-            NotAsNegationOperatorSub::SuggestNotLogical
+            errors::NotAsNegationOperatorSub::SuggestNotLogical
         } else {
-            NotAsNegationOperatorSub::SuggestNotDefault
+            errors::NotAsNegationOperatorSub::SuggestNotDefault
         };
 
-        self.sess.emit_err(NotAsNegationOperator {
+        self.sess.emit_err(errors::NotAsNegationOperator {
             negated: negated_token.span,
             negated_desc: super::token_descr(&negated_token),
             // Span the `not` plus trailing whitespace to avoid
@@ -739,7 +723,7 @@ fn parse_assoc_op_cast(
                         match self.parse_labeled_expr(label, false) {
                             Ok(expr) => {
                                 type_err.cancel();
-                                self.sess.emit_err(MalformedLoopLabel {
+                                self.sess.emit_err(errors::MalformedLoopLabel {
                                     span: label.ident.span,
                                     correct_label: label.ident,
                                 });
@@ -764,20 +748,22 @@ fn parse_assoc_op_cast(
                         );
 
                         let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);
-                        let suggestion = ComparisonOrShiftInterpretedAsGenericSugg {
+                        let suggestion = errors::ComparisonOrShiftInterpretedAsGenericSugg {
                             left: expr.span.shrink_to_lo(),
                             right: expr.span.shrink_to_hi(),
                         };
 
                         match self.token.kind {
-                            token::Lt => self.sess.emit_err(ComparisonInterpretedAsGeneric {
-                                comparison: self.token.span,
-                                r#type: path,
-                                args: args_span,
-                                suggestion,
-                            }),
+                            token::Lt => {
+                                self.sess.emit_err(errors::ComparisonInterpretedAsGeneric {
+                                    comparison: self.token.span,
+                                    r#type: path,
+                                    args: args_span,
+                                    suggestion,
+                                })
+                            }
                             token::BinOp(token::Shl) => {
-                                self.sess.emit_err(ShiftInterpretedAsGeneric {
+                                self.sess.emit_err(errors::ShiftInterpretedAsGeneric {
                                     shift: self.token.span,
                                     r#type: path,
                                     args: args_span,
@@ -918,7 +904,7 @@ fn parse_borrow_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
     }
 
     fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
-        self.sess.emit_err(LifetimeInBorrowExpression { span, lifetime_span: lt_span });
+        self.sess.emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span });
     }
 
     /// Parse `mut?` or `raw [ const | mut ]`.
@@ -1212,14 +1198,14 @@ fn maybe_recover_struct_lit_bad_delims(
                         let close_paren = self.prev_token.span;
                         let span = lo.to(self.prev_token.span);
                         if !fields.is_empty() {
-                            let mut replacement_err = ParenthesesWithStructFields {
+                            let mut replacement_err = errors::ParenthesesWithStructFields {
                                 span,
                                 r#type: path,
-                                braces_for_struct: BracesForStructLiteral {
+                                braces_for_struct: errors::BracesForStructLiteral {
                                     first: open_paren,
                                     second: close_paren,
                                 },
-                                no_fields_for_fn: NoFieldsForFnCall {
+                                no_fields_for_fn: errors::NoFieldsForFnCall {
                                     fields: fields
                                         .into_iter()
                                         .map(|field| field.span.until(field.expr.span))
@@ -1286,7 +1272,7 @@ fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Exp
         } else {
             // Field access `expr.f`
             if let Some(args) = seg.args {
-                self.sess.emit_err(FieldExpressionWithGeneric(args.span()));
+                self.sess.emit_err(errors::FieldExpressionWithGeneric(args.span()));
             }
 
             let span = lo.to(self.prev_token.span);
@@ -1500,7 +1486,7 @@ fn parse_path_start_expr(&mut self) -> PResult<'a, P<Expr>> {
         let (span, kind) = if self.eat(&token::Not) {
             // MACRO INVOCATION expression
             if qself.is_some() {
-                self.sess.emit_err(MacroInvocationWithQualifiedPath(path.span));
+                self.sess.emit_err(errors::MacroInvocationWithQualifiedPath(path.span));
             }
             let lo = path.span;
             let mac = P(MacCall {
@@ -1550,7 +1536,7 @@ fn parse_labeled_expr(
         {
             let (lit, _) =
                 self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| {
-                    self_.sess.create_err(UnexpectedTokenAfterLabel {
+                    self_.sess.create_err(errors::UnexpectedTokenAfterLabel {
                         span: self_.token.span,
                         remove_label: None,
                         enclose_in_block: None,
@@ -1562,7 +1548,7 @@ fn parse_labeled_expr(
             && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
         {
             // We're probably inside of a `Path<'a>` that needs a turbofish
-            self.sess.emit_err(UnexpectedTokenAfterLabel {
+            self.sess.emit_err(errors::UnexpectedTokenAfterLabel {
                 span: self.token.span,
                 remove_label: None,
                 enclose_in_block: None,
@@ -1570,7 +1556,7 @@ fn parse_labeled_expr(
             consume_colon = false;
             Ok(self.mk_expr_err(lo))
         } else {
-            let mut err = UnexpectedTokenAfterLabel {
+            let mut err = errors::UnexpectedTokenAfterLabel {
                 span: self.token.span,
                 remove_label: None,
                 enclose_in_block: None,
@@ -1606,7 +1592,7 @@ fn visit_expr_post(&mut self, ex: &'ast Expr) {
                     return expr;
                 }
 
-                err.enclose_in_block = Some(UnexpectedTokenAfterLabelSugg {
+                err.enclose_in_block = Some(errors::UnexpectedTokenAfterLabelSugg {
                     left: span.shrink_to_lo(),
                     right: span.shrink_to_hi(),
                 });
@@ -1622,7 +1608,7 @@ fn visit_expr_post(&mut self, ex: &'ast Expr) {
         }?;
 
         if !ate_colon && consume_colon {
-            self.sess.emit_err(RequireColonAfterLabeledExpression {
+            self.sess.emit_err(errors::RequireColonAfterLabeledExpression {
                 span: expr.span,
                 label: lo,
                 label_end: lo.shrink_to_hi(),
@@ -1671,7 +1657,7 @@ fn recover_do_catch(&mut self) -> PResult<'a, P<Expr>> {
         self.bump(); // `catch`
 
         let span = lo.to(self.prev_token.span);
-        self.sess.emit_err(DoCatchSyntaxRemoved { span });
+        self.sess.emit_err(errors::DoCatchSyntaxRemoved { span });
 
         self.parse_try_block(lo)
     }
@@ -1719,9 +1705,9 @@ fn parse_break_expr(&mut self) -> PResult<'a, P<Expr>> {
             // 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, true)?;
-            self.sess.emit_err(LabeledLoopInBreak {
+            self.sess.emit_err(errors::LabeledLoopInBreak {
                 span: lexpr.span,
-                sub: WrapExpressionInParentheses {
+                sub: errors::WrapExpressionInParentheses {
                     left: lexpr.span.shrink_to_lo(),
                     right: lexpr.span.shrink_to_hi(),
                 },
@@ -1841,7 +1827,7 @@ fn handle_missing_lit<L>(
             };
             if let Some(expr) = expr {
                 if matches!(expr.kind, ExprKind::Err) {
-                    let mut err = InvalidInterpolatedExpression { span: self.token.span }
+                    let mut err = errors::InvalidInterpolatedExpression { span: self.token.span }
                         .into_diagnostic(&self.sess.span_diagnostic);
                     err.downgrade_to_delayed_bug();
                     return Err(err);
@@ -1902,7 +1888,7 @@ fn recover_after_dot(&mut self) -> Option<Token> {
             });
             if let Some(token) = &recovered {
                 self.bump();
-                self.sess.emit_err(FloatLiteralRequiresIntegerPart {
+                self.sess.emit_err(errors::FloatLiteralRequiresIntegerPart {
                     span: token.span,
                     correct: pprust::token_to_string(token).into_owned(),
                 });
@@ -1963,13 +1949,17 @@ pub(super) fn expect_no_tuple_index_suffix(&self, span: Span, suffix: Symbol) {
         if [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suffix) {
             // #59553: warn instead of reject out of hand to allow the fix to percolate
             // through the ecosystem when people fix their macros
-            self.sess.emit_warning(InvalidLiteralSuffixOnTupleIndex {
+            self.sess.emit_warning(errors::InvalidLiteralSuffixOnTupleIndex {
                 span,
                 suffix,
                 exception: Some(()),
             });
         } else {
-            self.sess.emit_err(InvalidLiteralSuffixOnTupleIndex { span, suffix, exception: None });
+            self.sess.emit_err(errors::InvalidLiteralSuffixOnTupleIndex {
+                span,
+                suffix,
+                exception: None,
+            });
         }
     }
 
@@ -2003,9 +1993,9 @@ fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option<P<Exp
         let mut snapshot = self.create_snapshot_for_diagnostic();
         match snapshot.parse_array_or_repeat_expr(Delimiter::Brace) {
             Ok(arr) => {
-                self.sess.emit_err(ArrayBracketsInsteadOfSpaces {
+                self.sess.emit_err(errors::ArrayBracketsInsteadOfSpaces {
                     span: arr.span,
-                    sub: ArrayBracketsInsteadOfSpacesSugg {
+                    sub: errors::ArrayBracketsInsteadOfSpacesSugg {
                         left: lo,
                         right: snapshot.prev_token.span,
                     },
@@ -2051,7 +2041,7 @@ fn suggest_missing_semicolon_before_array(
                         .span_to_snippet(snapshot.token.span)
                         .map_or(false, |snippet| snippet == "]") =>
                 {
-                    return Err(MissingSemicolonBeforeArray {
+                    return Err(errors::MissingSemicolonBeforeArray {
                         open_delim: open_delim_span,
                         semicolon: prev_span.shrink_to_hi(),
                     }.into_diagnostic(&self.sess.span_diagnostic));
@@ -2077,7 +2067,7 @@ pub(super) fn parse_block_expr(
         }
 
         if self.token.is_whole_block() {
-            self.sess.emit_err(InvalidBlockMacroSegment {
+            self.sess.emit_err(errors::InvalidBlockMacroSegment {
                 span: self.token.span,
                 context: lo.to(self.token.span),
             });
@@ -2109,7 +2099,7 @@ fn parse_closure_expr(&mut self) -> PResult<'a, P<Expr>> {
             ClosureBinder::NotPresent
         };
 
-        let constness = self.parse_constness(Case::Sensitive);
+        let constness = self.parse_closure_constness(Case::Sensitive);
 
         let movability =
             if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
@@ -2181,7 +2171,7 @@ fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
             // Check for `move async` and recover
             if self.check_keyword(kw::Async) {
                 let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
-                Err(AsyncMoveOrderIncorrect { span: move_async_span }
+                Err(errors::AsyncMoveOrderIncorrect { span: move_async_span }
                     .into_diagnostic(&self.sess.span_diagnostic))
             } else {
                 Ok(CaptureBy::Value)
@@ -2259,17 +2249,17 @@ fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<
             let block = match &mut cond.kind {
                 ExprKind::Binary(Spanned { span: binop_span, .. }, _, right)
                     if let ExprKind::Block(_, None) = right.kind => {
-                        self.sess.emit_err(IfExpressionMissingThenBlock {
+                        self.sess.emit_err(errors::IfExpressionMissingThenBlock {
                             if_span: lo,
                             missing_then_block_sub:
-                                IfExpressionMissingThenBlockSub::UnfinishedCondition(cond_span.shrink_to_lo().to(*binop_span)),
+                                errors::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()))
                     },
                 ExprKind::Block(_, None) => {
-                    self.sess.emit_err(IfExpressionMissingCondition {
+                    self.sess.emit_err(errors::IfExpressionMissingCondition {
                         if_span: lo.shrink_to_hi(),
                         block_span: self.sess.source_map().start_point(cond_span),
                     });
@@ -2291,11 +2281,11 @@ fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<
                 block
             } else {
                 let let_else_sub = matches!(cond.kind, ExprKind::Let(..))
-                    .then(|| IfExpressionLetSomeSub { if_span: lo.until(cond_span) });
+                    .then(|| errors::IfExpressionLetSomeSub { if_span: lo.until(cond_span) });
 
-                self.sess.emit_err(IfExpressionMissingThenBlock {
+                self.sess.emit_err(errors::IfExpressionMissingThenBlock {
                     if_span: lo,
-                    missing_then_block_sub: IfExpressionMissingThenBlockSub::AddThenBlock(
+                    missing_then_block_sub: errors::IfExpressionMissingThenBlockSub::AddThenBlock(
                         cond_span.shrink_to_hi(),
                     ),
                     let_else_sub,
@@ -2351,7 +2341,7 @@ fn parse_let_expr(&mut self) -> PResult<'a, P<Expr>> {
             TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _)
         );
         if !self.restrictions.contains(Restrictions::ALLOW_LET) || not_in_chain {
-            self.sess.emit_err(ExpectedExpressionFoundLet { span: self.token.span });
+            self.sess.emit_err(errors::ExpectedExpressionFoundLet { span: self.token.span });
         }
 
         self.bump(); // Eat `let` token
@@ -2363,7 +2353,7 @@ fn parse_let_expr(&mut self) -> PResult<'a, P<Expr>> {
             CommaRecoveryMode::LikelyTuple,
         )?;
         if self.token == token::EqEq {
-            self.sess.emit_err(ExpectedEqForLetExpr {
+            self.sess.emit_err(errors::ExpectedEqForLetExpr {
                 span: self.token.span,
                 sugg_span: self.token.span,
             });
@@ -2398,7 +2388,7 @@ fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
                     if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
                         && classify::expr_requires_semi_to_be_stmt(&cond) =>
                 {
-                    self.sess.emit_err(ExpectedElseBlock {
+                    self.sess.emit_err(errors::ExpectedElseBlock {
                         first_tok_span,
                         first_tok,
                         else_span,
@@ -2438,7 +2428,7 @@ fn error_on_if_block_attrs(
             [x0 @ xn] | [x0, .., xn] => (x0.span.to(xn.span), xn.span),
         };
         let ctx = if is_ctx_else { "else" } else { "if" };
-        self.sess.emit_err(OuterAttributeNotAllowedOnIfElse {
+        self.sess.emit_err(errors::OuterAttributeNotAllowedOnIfElse {
             last,
             branch_span,
             ctx_span,
@@ -2451,7 +2441,7 @@ fn error_on_extra_if(&mut self, cond: &P<Expr>) -> PResult<'a, ()> {
         if let ExprKind::Binary(Spanned { span: binop_span, node: binop}, _, right) = &cond.kind &&
             let BinOpKind::And = binop &&
             let ExprKind::If(cond, ..) = &right.kind {
-                    Err(self.sess.create_err(UnexpectedIfWithIf(binop_span.shrink_to_hi().to(cond.span.shrink_to_lo()))))
+                    Err(self.sess.create_err(errors::UnexpectedIfWithIf(binop_span.shrink_to_hi().to(cond.span.shrink_to_lo()))))
             } else {
                 Ok(())
             }
@@ -2481,6 +2471,21 @@ fn parse_for_expr(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a,
 
         let pat = self.recover_parens_around_for_head(pat, begin_paren);
 
+        // Recover from missing expression in `for` loop
+        if matches!(expr.kind, ExprKind::Block(..))
+            && !matches!(self.token.kind, token::OpenDelim(token::Delimiter::Brace))
+            && self.may_recover()
+        {
+            self.sess
+                .emit_err(errors::MissingExpressionInForLoop { span: expr.span.shrink_to_lo() });
+            let err_expr = self.mk_expr(expr.span, ExprKind::Err);
+            let block = self.mk_block(vec![], BlockCheckMode::Default, self.prev_token.span);
+            return Ok(self.mk_expr(
+                lo.to(self.prev_token.span),
+                ExprKind::ForLoop(pat, err_expr, block, opt_label),
+            ));
+        }
+
         let (attrs, loop_block) = self.parse_inner_attrs_and_block()?;
 
         let kind = ExprKind::ForLoop(pat, expr, loop_block, opt_label);
@@ -2492,12 +2497,12 @@ fn error_missing_in_for_loop(&mut self) {
             // Possibly using JS syntax (#75311).
             let span = self.token.span;
             self.bump();
-            (span, MissingInInForLoopSub::InNotOf)
+            (span, errors::MissingInInForLoopSub::InNotOf)
         } else {
-            (self.prev_token.span.between(self.token.span), MissingInInForLoopSub::AddIn)
+            (self.prev_token.span.between(self.token.span), errors::MissingInInForLoopSub::AddIn)
         };
 
-        self.sess.emit_err(MissingInInForLoop { span, sub: sub(span) });
+        self.sess.emit_err(errors::MissingInInForLoop { span, sub: sub(span) });
     }
 
     /// Parses a `while` or `while let` expression (`while` token already eaten).
@@ -2601,17 +2606,17 @@ fn parse_arm_body_missing_braces(
         let err = |this: &Parser<'_>, stmts: Vec<ast::Stmt>| {
             let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
 
-            this.sess.emit_err(MatchArmBodyWithoutBraces {
+            this.sess.emit_err(errors::MatchArmBodyWithoutBraces {
                 statements: span,
                 arrow: arrow_span,
                 num_statements: stmts.len(),
                 sub: if stmts.len() > 1 {
-                    MatchArmBodyWithoutBracesSugg::AddBraces {
+                    errors::MatchArmBodyWithoutBracesSugg::AddBraces {
                         left: span.shrink_to_lo(),
                         right: span.shrink_to_hi(),
                     }
                 } else {
-                    MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp }
+                    errors::MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp }
                 },
             });
             this.mk_expr_err(span)
@@ -2802,7 +2807,7 @@ fn check_let_expr(expr: &Expr) -> (bool, bool) {
                                 .is_ok();
                             if pattern_follows && snapshot.check(&TokenKind::FatArrow) {
                                 err.cancel();
-                                this.sess.emit_err(MissingCommaAfterMatchArm {
+                                this.sess.emit_err(errors::MissingCommaAfterMatchArm {
                                     span: hi.shrink_to_hi(),
                                 });
                                 return Ok(true);
@@ -2834,7 +2839,7 @@ fn check_let_expr(expr: &Expr) -> (bool, bool) {
     fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
         let (attrs, body) = self.parse_inner_attrs_and_block()?;
         if self.eat_keyword(kw::Catch) {
-            Err(CatchAfterTry { span: self.prev_token.span }
+            Err(errors::CatchAfterTry { span: self.prev_token.span }
                 .into_diagnostic(&self.sess.span_diagnostic))
         } else {
             let span = span_lo.to(body.span);
@@ -2910,9 +2915,9 @@ fn maybe_parse_struct_expr(
             let expr = self.parse_struct_expr(qself.clone(), path.clone(), true);
             if let (Ok(expr), false) = (&expr, struct_allowed) {
                 // This is a struct literal, but we don't can't accept them here.
-                self.sess.emit_err(StructLiteralNotAllowedHere {
+                self.sess.emit_err(errors::StructLiteralNotAllowedHere {
                     span: expr.span,
-                    sub: StructLiteralNotAllowedHereSugg {
+                    sub: errors::StructLiteralNotAllowedHereSugg {
                         left: path.span.shrink_to_lo(),
                         right: expr.span.shrink_to_hi(),
                     },
@@ -2935,8 +2940,8 @@ pub(super) fn parse_struct_fields(
 
         let mut async_block_err = |e: &mut Diagnostic, span: Span| {
             recover_async = true;
-            AsyncBlockIn2015 { span }.add_to_diagnostic(e);
-            HelpUseLatestEdition::new().add_to_diagnostic(e);
+            errors::AsyncBlockIn2015 { span }.add_to_diagnostic(e);
+            errors::HelpUseLatestEdition::new().add_to_diagnostic(e);
         };
 
         while self.token != token::CloseDelim(close_delim) {
@@ -3080,7 +3085,7 @@ fn recover_struct_comma_after_dotdot(&mut self, span: Span) {
         if self.token != token::Comma {
             return;
         }
-        self.sess.emit_err(CommaAfterBaseStruct {
+        self.sess.emit_err(errors::CommaAfterBaseStruct {
             span: span.to(self.prev_token.span),
             comma: self.token.span,
         });
@@ -3093,7 +3098,7 @@ fn recover_struct_field_dots(&mut self, close_delim: Delimiter) -> bool {
         {
             // recover from typo of `...`, suggest `..`
             let span = self.prev_token.span;
-            self.sess.emit_err(MissingDotDot { token_span: span, sugg_span: span });
+            self.sess.emit_err(errors::MissingDotDot { token_span: span, sugg_span: span });
             return true;
         }
         false
@@ -3161,18 +3166,18 @@ fn error_on_eq_field_init(&self, field_name: Ident) {
             return;
         }
 
-        self.sess.emit_err(EqFieldInit {
+        self.sess.emit_err(errors::EqFieldInit {
             span: self.token.span,
             eq: field_name.span.shrink_to_hi().to(self.token.span),
         });
     }
 
     fn err_dotdotdot_syntax(&self, span: Span) {
-        self.sess.emit_err(DotDotDot { span });
+        self.sess.emit_err(errors::DotDotDot { span });
     }
 
     fn err_larrow_operator(&self, span: Span) {
-        self.sess.emit_err(LeftArrowOperator { span });
+        self.sess.emit_err(errors::LeftArrowOperator { span });
     }
 
     fn mk_assign_op(&self, binop: BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ExprKind {
index 585dfc518b325c1735f89e1dec201179d0840d25..23f49ec55a18ddda7a413b3de172b7df7b05cc01 100644 (file)
@@ -1,5 +1,6 @@
 use crate::errors::{
-    MultipleWhereClauses, UnexpectedSelfInGenericParameters, WhereClauseBeforeTupleStructBody,
+    MultipleWhereClauses, UnexpectedDefaultValueForLifetimeInGenericParameters,
+    UnexpectedSelfInGenericParameters, WhereClauseBeforeTupleStructBody,
     WhereClauseBeforeTupleStructBodySugg,
 };
 
@@ -145,6 +146,20 @@ pub(super) fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericPar
                         } else {
                             (None, Vec::new())
                         };
+
+                        if this.check_noexpect(&token::Eq)
+                            && this.look_ahead(1, |t| t.is_lifetime())
+                        {
+                            let lo = this.token.span;
+                            // Parse `= 'lifetime`.
+                            this.bump(); // `=`
+                            this.bump(); // `'lifetime`
+                            let span = lo.to(this.prev_token.span);
+                            this.sess.emit_err(
+                                UnexpectedDefaultValueForLifetimeInGenericParameters { span },
+                            );
+                        }
+
                         Some(ast::GenericParam {
                             ident: lifetime.ident,
                             id: lifetime.id,
index 2ea55f838a37e3f1022476a98a91205e51a6466d..0cb88f3c3a91697726fd3cde44b7774a7cea8c3d 100644 (file)
@@ -732,9 +732,10 @@ fn check_const_arg(&mut self) -> bool {
     fn check_const_closure(&self) -> bool {
         self.is_keyword_ahead(0, &[kw::Const])
             && self.look_ahead(1, |t| match &t.kind {
-                token::Ident(kw::Move | kw::Static | kw::Async, _)
-                | token::OrOr
-                | token::BinOp(token::Or) => true,
+                // async closures do not work with const closures, so we do not parse that here.
+                token::Ident(kw::Move | kw::Static, _) | token::OrOr | token::BinOp(token::Or) => {
+                    true
+                }
                 _ => false,
             })
     }
@@ -1198,8 +1199,18 @@ fn parse_unsafety(&mut self, case: Case) -> Unsafe {
 
     /// Parses constness: `const` or nothing.
     fn parse_constness(&mut self, case: Case) -> Const {
-        // Avoid const blocks to be parsed as const items
-        if self.look_ahead(1, |t| t != &token::OpenDelim(Delimiter::Brace))
+        self.parse_constness_(case, false)
+    }
+
+    /// Parses constness for closures
+    fn parse_closure_constness(&mut self, case: Case) -> Const {
+        self.parse_constness_(case, true)
+    }
+
+    fn parse_constness_(&mut self, case: Case, is_closure: bool) -> Const {
+        // Avoid const blocks and const closures to be parsed as const items
+        if (self.check_const_closure() == is_closure)
+            && self.look_ahead(1, |t| t != &token::OpenDelim(Delimiter::Brace))
             && self.eat_keyword_case(kw::Const, case)
         {
             Const::Yes(self.prev_token.uninterpolated_span())
index 647639b9b62b4244b5918205448b01f7ba8ef94d..3afda5f69f0e1f4eceb99a29858507af08b1071c 100644 (file)
@@ -7,12 +7,7 @@
 use super::{
     AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode,
 };
-use crate::errors::{
-    AssignmentElseNotAllowed, CompoundAssignmentExpressionInLet, ConstLetMutuallyExclusive,
-    DocCommentDoesNotDocumentAnything, ExpectedStatementAfterOuterAttr, InvalidCurlyInLetElse,
-    InvalidExpressionInLetElse, InvalidIdentiferStartsWithNumber, InvalidVariableDeclaration,
-    InvalidVariableDeclarationSub, WrapExpressionInParentheses,
-};
+use crate::errors;
 use crate::maybe_whole;
 
 use rustc_ast as ast;
@@ -64,29 +59,33 @@ pub(crate) fn parse_stmt_without_recovery(
         if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) {
             self.bump();
             let mut_let_span = lo.to(self.token.span);
-            self.sess.emit_err(InvalidVariableDeclaration {
+            self.sess.emit_err(errors::InvalidVariableDeclaration {
                 span: mut_let_span,
-                sub: InvalidVariableDeclarationSub::SwitchMutLetOrder(mut_let_span),
+                sub: errors::InvalidVariableDeclarationSub::SwitchMutLetOrder(mut_let_span),
             });
         }
 
         Ok(Some(if self.token.is_keyword(kw::Let) {
             self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
         } else if self.is_kw_followed_by_ident(kw::Mut) && self.may_recover() {
-            self.recover_stmt_local_after_let(lo, attrs, InvalidVariableDeclarationSub::MissingLet)?
+            self.recover_stmt_local_after_let(
+                lo,
+                attrs,
+                errors::InvalidVariableDeclarationSub::MissingLet,
+            )?
         } else if self.is_kw_followed_by_ident(kw::Auto) && self.may_recover() {
             self.bump(); // `auto`
             self.recover_stmt_local_after_let(
                 lo,
                 attrs,
-                InvalidVariableDeclarationSub::UseLetNotAuto,
+                errors::InvalidVariableDeclarationSub::UseLetNotAuto,
             )?
         } else if self.is_kw_followed_by_ident(sym::var) && self.may_recover() {
             self.bump(); // `var`
             self.recover_stmt_local_after_let(
                 lo,
                 attrs,
-                InvalidVariableDeclarationSub::UseLetNotVar,
+                errors::InvalidVariableDeclarationSub::UseLetNotVar,
             )?
         } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
             // We have avoided contextual keywords like `union`, items with `crate` visibility,
@@ -124,7 +123,7 @@ pub(crate) fn parse_stmt_without_recovery(
                 let bl = self.parse_block()?;
                 // Destructuring assignment ... else.
                 // This is not allowed, but point it out in a nice way.
-                self.sess.emit_err(AssignmentElseNotAllowed { span: e.span.to(bl.span) });
+                self.sess.emit_err(errors::AssignmentElseNotAllowed { span: e.span.to(bl.span) });
             }
             self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
         } else {
@@ -217,12 +216,12 @@ fn error_outer_attrs(&self, attrs: AttrWrapper) {
         && let attrs = attrs.take_for_recovery(self.sess)
         && let attrs @ [.., last] = &*attrs {
             if last.is_doc_comment() {
-                self.sess.emit_err(DocCommentDoesNotDocumentAnything {
+                self.sess.emit_err(errors::DocCommentDoesNotDocumentAnything {
                     span: last.span,
                     missing_comma: None,
                 });
             } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) {
-                self.sess.emit_err(ExpectedStatementAfterOuterAttr { span: last.span });
+                self.sess.emit_err(errors::ExpectedStatementAfterOuterAttr { span: last.span });
             }
         }
     }
@@ -231,7 +230,7 @@ fn recover_stmt_local_after_let(
         &mut self,
         lo: Span,
         attrs: AttrWrapper,
-        subdiagnostic: fn(Span) -> InvalidVariableDeclarationSub,
+        subdiagnostic: fn(Span) -> errors::InvalidVariableDeclarationSub,
     ) -> PResult<'a, Stmt> {
         let stmt =
             self.collect_tokens_trailing_token(attrs, ForceCollect::Yes, |this, attrs| {
@@ -242,7 +241,7 @@ fn recover_stmt_local_after_let(
                     TrailingToken::None,
                 ))
             })?;
-        self.sess.emit_err(InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
+        self.sess.emit_err(errors::InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
         Ok(stmt)
     }
 
@@ -270,7 +269,7 @@ fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
         let lo = self.prev_token.span;
 
         if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) {
-            self.sess.emit_err(ConstLetMutuallyExclusive { span: lo.to(self.token.span) });
+            self.sess.emit_err(errors::ConstLetMutuallyExclusive { span: lo.to(self.token.span) });
             self.bump();
         }
 
@@ -373,7 +372,7 @@ pub fn report_invalid_identifier_error(&mut self) -> PResult<'a, ()> {
             rustc_ast::MetaItemLit::from_token(&self.token).is_none() &&
             (lit.kind == token::LitKind::Integer || lit.kind == token::LitKind::Float) &&
             self.look_ahead(1, |t| matches!(t.kind, token::Eq) || matches!(t.kind, token::Colon ) ) {
-                return Err(self.sess.create_err(InvalidIdentiferStartsWithNumber { span: self.token.span }));
+                return Err(self.sess.create_err(errors::InvalidIdentiferStartsWithNumber { span: self.token.span }));
         }
         Ok(())
     }
@@ -381,10 +380,10 @@ pub fn report_invalid_identifier_error(&mut self) -> PResult<'a, ()> {
     fn check_let_else_init_bool_expr(&self, init: &ast::Expr) {
         if let ast::ExprKind::Binary(op, ..) = init.kind {
             if op.node.lazy() {
-                self.sess.emit_err(InvalidExpressionInLetElse {
+                self.sess.emit_err(errors::InvalidExpressionInLetElse {
                     span: init.span,
                     operator: op.node.to_string(),
-                    sugg: WrapExpressionInParentheses {
+                    sugg: errors::WrapExpressionInParentheses {
                         left: init.span.shrink_to_lo(),
                         right: init.span.shrink_to_hi(),
                     },
@@ -395,9 +394,9 @@ fn check_let_else_init_bool_expr(&self, init: &ast::Expr) {
 
     fn check_let_else_init_trailing_brace(&self, init: &ast::Expr) {
         if let Some(trailing) = classify::expr_trailing_brace(init) {
-            self.sess.emit_err(InvalidCurlyInLetElse {
+            self.sess.emit_err(errors::InvalidCurlyInLetElse {
                 span: trailing.span.with_lo(trailing.span.hi() - BytePos(1)),
-                sugg: WrapExpressionInParentheses {
+                sugg: errors::WrapExpressionInParentheses {
                     left: trailing.span.shrink_to_lo(),
                     right: trailing.span.shrink_to_hi(),
                 },
@@ -410,7 +409,8 @@ fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option<P<Expr>
         let eq_consumed = match self.token.kind {
             token::BinOpEq(..) => {
                 // Recover `let x <op>= 1` as `let x = 1`
-                self.sess.emit_err(CompoundAssignmentExpressionInLet { span: self.token.span });
+                self.sess
+                    .emit_err(errors::CompoundAssignmentExpressionInLet { span: self.token.span });
                 self.bump();
                 true
             }
index 644d701be0caa79ddcbfcb7e04bcc321309db8de..238ec9ca30f704a99b0e72eb65e8d58454180062 100644 (file)
@@ -4,11 +4,7 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use crate::errors::{
-    self, AttrApplication, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel, ObjectLifetimeErr,
-    OnlyHasEffectOn, ProcMacroDiffArguments, ProcMacroInvalidAbi, ProcMacroMissingArguments,
-    ProcMacroTypeError, ProcMacroUnsafe, TransparentIncompatible, UnrecognizedReprHint,
-};
+use crate::errors;
 use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{fluent, Applicability, IntoDiagnosticArg, MultiSpan};
@@ -399,7 +395,7 @@ fn check_generic_attr(
                 UNUSED_ATTRIBUTES,
                 hir_id,
                 attr.span,
-                OnlyHasEffectOn {
+                errors::OnlyHasEffectOn {
                     attr_name: attr.name_or_empty(),
                     target_name: allowed_target.name().replace(' ', "_"),
                 },
@@ -468,7 +464,7 @@ fn check_object_lifetime_default(&self, hir_id: HirId) {
                     ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
                     ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
                 };
-                tcx.sess.emit_err(ObjectLifetimeErr { span: p.span, repr });
+                tcx.sess.emit_err(errors::ObjectLifetimeErr { span: p.span, repr });
             }
         }
     }
@@ -1715,7 +1711,7 @@ fn check_repr(
                     match target {
                         Target::Struct | Target::Union | Target::Enum => continue,
                         _ => {
-                            self.tcx.sess.emit_err(AttrApplication::StructEnumUnion {
+                            self.tcx.sess.emit_err(errors::AttrApplication::StructEnumUnion {
                                 hint_span: hint.span(),
                                 span,
                             });
@@ -1736,16 +1732,18 @@ fn check_repr(
                     match target {
                         Target::Struct | Target::Union | Target::Enum | Target::Fn => continue,
                         _ => {
-                            self.tcx.sess.emit_err(AttrApplication::StructEnumFunctionUnion {
-                                hint_span: hint.span(),
-                                span,
-                            });
+                            self.tcx.sess.emit_err(
+                                errors::AttrApplication::StructEnumFunctionUnion {
+                                    hint_span: hint.span(),
+                                    span,
+                                },
+                            );
                         }
                     }
                 }
                 sym::packed => {
                     if target != Target::Struct && target != Target::Union {
-                        self.tcx.sess.emit_err(AttrApplication::StructUnion {
+                        self.tcx.sess.emit_err(errors::AttrApplication::StructUnion {
                             hint_span: hint.span(),
                             span,
                         });
@@ -1756,9 +1754,10 @@ fn check_repr(
                 sym::simd => {
                     is_simd = true;
                     if target != Target::Struct {
-                        self.tcx
-                            .sess
-                            .emit_err(AttrApplication::Struct { hint_span: hint.span(), span });
+                        self.tcx.sess.emit_err(errors::AttrApplication::Struct {
+                            hint_span: hint.span(),
+                            span,
+                        });
                     } else {
                         continue;
                     }
@@ -1768,7 +1767,7 @@ fn check_repr(
                     match target {
                         Target::Struct | Target::Union | Target::Enum => continue,
                         _ => {
-                            self.tcx.sess.emit_err(AttrApplication::StructEnumUnion {
+                            self.tcx.sess.emit_err(errors::AttrApplication::StructEnumUnion {
                                 hint_span: hint.span(),
                                 span,
                             });
@@ -1789,15 +1788,16 @@ fn check_repr(
                 | sym::usize => {
                     int_reprs += 1;
                     if target != Target::Enum {
-                        self.tcx
-                            .sess
-                            .emit_err(AttrApplication::Enum { hint_span: hint.span(), span });
+                        self.tcx.sess.emit_err(errors::AttrApplication::Enum {
+                            hint_span: hint.span(),
+                            span,
+                        });
                     } else {
                         continue;
                     }
                 }
                 _ => {
-                    self.tcx.sess.emit_err(UnrecognizedReprHint { span: hint.span() });
+                    self.tcx.sess.emit_err(errors::UnrecognizedReprHint { span: hint.span() });
                     continue;
                 }
             };
@@ -1810,9 +1810,10 @@ fn check_repr(
         // Error on repr(transparent, <anything else>).
         if is_transparent && hints.len() > 1 {
             let hint_spans: Vec<_> = hint_spans.clone().collect();
-            self.tcx
-                .sess
-                .emit_err(TransparentIncompatible { hint_spans, target: target.to_string() });
+            self.tcx.sess.emit_err(errors::TransparentIncompatible {
+                hint_spans,
+                target: target.to_string(),
+            });
         }
         // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
         if (int_reprs > 1)
@@ -1965,7 +1966,7 @@ fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool {
         match std::fs::File::open(&file) {
             Ok(_) => true,
             Err(error) => {
-                self.tcx.sess.emit_err(DebugVisualizerUnreadable {
+                self.tcx.sess.emit_err(errors::DebugVisualizerUnreadable {
                     span: meta_item.span,
                     file: &file,
                     error,
@@ -2175,12 +2176,15 @@ fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
             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() });
+                tcx.sess.emit_err(errors::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 });
+                tcx.sess.emit_err(errors::ProcMacroUnsafe { span: hir_sig.span });
                 self.abort.set(true);
             }
 
@@ -2188,7 +2192,7 @@ fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
 
             // Typecheck the output
             if !drcx.types_may_unify(output, tokenstream) {
-                tcx.sess.emit_err(ProcMacroTypeError {
+                tcx.sess.emit_err(errors::ProcMacroTypeError {
                     span: hir_sig.decl.output.span(),
                     found: output,
                     kind,
@@ -2198,7 +2202,7 @@ fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
             }
 
             if sig.inputs().len() < expected_input_count {
-                tcx.sess.emit_err(ProcMacroMissingArguments {
+                tcx.sess.emit_err(errors::ProcMacroMissingArguments {
                     expected_input_count,
                     span: hir_sig.span,
                     kind,
@@ -2213,7 +2217,7 @@ fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
                     sig.inputs().iter().zip(hir_sig.decl.inputs).take(expected_input_count)
                 {
                     if !drcx.types_may_unify(*arg, tokenstream) {
-                        tcx.sess.emit_err(ProcMacroTypeError {
+                        tcx.sess.emit_err(errors::ProcMacroTypeError {
                             span: input.span,
                             found: *arg,
                             kind,
@@ -2228,7 +2232,7 @@ fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
             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 {
+                tcx.sess.emit_err(errors::ProcMacroDiffArguments {
                     span: begin.span.to(end.span),
                     count: excess.len(),
                     kind,
@@ -2378,7 +2382,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
         if attr.style == AttrStyle::Inner {
             for attr_to_check in ATTRS_TO_CHECK {
                 if attr.has_name(*attr_to_check) {
-                    tcx.sess.emit_err(InvalidAttrAtCrateLevel {
+                    tcx.sess.emit_err(errors::InvalidAttrAtCrateLevel {
                         span: attr.span,
                         snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(),
                         name: *attr_to_check,
index 47911aef25d4fe1f240e1dc432d688e96338490e..7299fc9705cc6036046b3d3036b561042931f123 100644 (file)
@@ -1,12 +1,7 @@
 //! A pass that annotates every item and method with its stability level,
 //! propagating default levels lexically from parent to children ast nodes.
 
-use crate::errors::{
-    self, CannotStabilizeDeprecated, DeprecatedAttribute, DuplicateFeatureErr,
-    FeatureOnlyOnNightly, ImpliedFeatureNotExist, InvalidDeprecationVersion, InvalidStability,
-    MissingConstErr, MissingConstStabAttr, MissingStabilityAttr, TraitImplConstStable,
-    UnknownFeature, UselessStability,
-};
+use crate::errors;
 use rustc_attr::{
     self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable,
     UnstableReason, VERSION_PLACEHOLDER,
@@ -185,7 +180,7 @@ fn annotate<F>(
                 {
                     self.tcx
                         .sess
-                        .emit_err(MissingConstErr { fn_sig_span: fn_sig.span, const_span });
+                        .emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span, const_span });
                 }
             }
         }
@@ -203,7 +198,7 @@ fn annotate<F>(
 
         if let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr {
             if stab.is_none() {
-                self.tcx.sess.emit_err(DeprecatedAttribute { span: *span });
+                self.tcx.sess.emit_err(errors::DeprecatedAttribute { span: *span });
             }
         }
 
@@ -219,7 +214,7 @@ fn annotate<F>(
             if kind == AnnotationKind::Prohibited
                 || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
             {
-                self.tcx.sess.emit_err(UselessStability { span, item_sp });
+                self.tcx.sess.emit_err(errors::UselessStability { span, item_sp });
             }
 
             debug!("annotate: found {:?}", stab);
@@ -235,15 +230,16 @@ fn annotate<F>(
                 {
                     match stab_v.parse::<u64>() {
                         Err(_) => {
-                            self.tcx.sess.emit_err(InvalidStability { span, item_sp });
+                            self.tcx.sess.emit_err(errors::InvalidStability { span, item_sp });
                             break;
                         }
                         Ok(stab_vp) => match dep_v.parse::<u64>() {
                             Ok(dep_vp) => match dep_vp.cmp(&stab_vp) {
                                 Ordering::Less => {
-                                    self.tcx
-                                        .sess
-                                        .emit_err(CannotStabilizeDeprecated { span, item_sp });
+                                    self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated {
+                                        span,
+                                        item_sp,
+                                    });
                                     break;
                                 }
                                 Ordering::Equal => continue,
@@ -251,9 +247,10 @@ fn annotate<F>(
                             },
                             Err(_) => {
                                 if dep_v != "TBD" {
-                                    self.tcx
-                                        .sess
-                                        .emit_err(InvalidDeprecationVersion { span, item_sp });
+                                    self.tcx.sess.emit_err(errors::InvalidDeprecationVersion {
+                                        span,
+                                        item_sp,
+                                    });
                                 }
                                 break;
                             }
@@ -527,7 +524,7 @@ fn check_missing_stability(&self, def_id: LocalDefId, span: Span) {
             && self.effective_visibilities.is_reachable(def_id)
         {
             let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
-            self.tcx.sess.emit_err(MissingStabilityAttr { span, descr });
+            self.tcx.sess.emit_err(errors::MissingStabilityAttr { span, descr });
         }
     }
 
@@ -555,7 +552,7 @@ fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
 
         if is_const && is_stable && missing_const_stability_attribute && is_reachable {
             let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
-            self.tcx.sess.emit_err(MissingConstStabAttr { span, descr });
+            self.tcx.sess.emit_err(errors::MissingConstStabAttr { span, descr });
         }
     }
 }
@@ -768,7 +765,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                         && *constness == hir::Constness::Const
                         && const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
                     {
-                        self.tcx.sess.emit_err(TraitImplConstStable { span: item.span });
+                        self.tcx.sess.emit_err(errors::TraitImplConstStable { span: item.span });
                     }
                 }
 
@@ -947,7 +944,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
         }
         if !lang_features.insert(feature) {
             // Warn if the user enables a lang feature multiple times.
-            tcx.sess.emit_err(DuplicateFeatureErr { span, feature });
+            tcx.sess.emit_err(errors::DuplicateFeatureErr { span, feature });
         }
     }
 
@@ -955,14 +952,14 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     let mut remaining_lib_features = FxIndexMap::default();
     for (feature, span) in declared_lib_features {
         if !tcx.sess.opts.unstable_features.is_nightly_build() {
-            tcx.sess.emit_err(FeatureOnlyOnNightly {
+            tcx.sess.emit_err(errors::FeatureOnlyOnNightly {
                 span: *span,
                 release_channel: env!("CFG_RELEASE_CHANNEL"),
             });
         }
         if remaining_lib_features.contains_key(&feature) {
             // Warn if the user enables a lib feature multiple times.
-            tcx.sess.emit_err(DuplicateFeatureErr { span: *span, feature: *feature });
+            tcx.sess.emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature });
         }
         remaining_lib_features.insert(feature, *span);
     }
@@ -1063,7 +1060,7 @@ fn check_features<'tcx>(
     }
 
     for (feature, span) in remaining_lib_features {
-        tcx.sess.emit_err(UnknownFeature { span, feature: *feature });
+        tcx.sess.emit_err(errors::UnknownFeature { span, feature: *feature });
     }
 
     for (implied_by, feature) in remaining_implications {
@@ -1074,7 +1071,7 @@ fn check_features<'tcx>(
             .map(|(_, span)| span)
             .or_else(|| local_defined_features.unstable.get(&feature))
             .expect("feature that implied another does not exist");
-        tcx.sess.emit_err(ImpliedFeatureNotExist { span, feature, implied_by });
+        tcx.sess.emit_err(errors::ImpliedFeatureNotExist { span, feature, implied_by });
     }
 
     // FIXME(#44232): the `used_features` table no longer exists, so we
index 832fdc9f01668f00c90b324ae8cd93679f12b30e..744cb77dd00cd1c7b5a2a9131a626eb63d952cb8 100644 (file)
@@ -13,6 +13,5 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
-rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_hir_analysis = { path = "../rustc_hir_analysis" }
 tracing = "0.1"
index 46e77626479c83ed7a09df9867c8eac3285674a2..21732d260354d995daa6185af1f183d4f95c61ad 100644 (file)
@@ -20,7 +20,6 @@ rustc-rayon-core = { version = "0.4.0", optional = true }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
-rustc_target = { path = "../rustc_target" }
 thin-vec = "0.2.9"
 tracing = "0.1"
 
index 77d0d0314fc17de7a36de449436e484118bec350..21c89cbc4f19da63e3e793815ef71d1e2922fc12 100644 (file)
 pub trait CacheSelector<'tcx, V> {
     type Cache
     where
-        V: Clone;
+        V: Copy;
     type ArenaCache;
 }
 
 pub trait QueryStorage {
     type Value: Debug;
-    type Stored: Clone;
+    type Stored: Copy;
 
     /// Store a value without putting it in the cache.
     /// This is meant to be used with cycle errors.
@@ -36,14 +36,7 @@ pub trait QueryCache: QueryStorage + Sized {
     /// It returns the shard index and a lock guard to the shard,
     /// which will be used if the query is not in the cache and we need
     /// to compute it.
-    fn lookup<R, OnHit>(
-        &self,
-        key: &Self::Key,
-        // `on_hit` can be called while holding a lock to the query state shard.
-        on_hit: OnHit,
-    ) -> Result<R, ()>
-    where
-        OnHit: FnOnce(&Self::Stored, DepNodeIndex) -> R;
+    fn lookup(&self, key: &Self::Key) -> Option<(Self::Stored, DepNodeIndex)>;
 
     fn complete(&self, key: Self::Key, value: Self::Value, index: DepNodeIndex) -> Self::Stored;
 
@@ -55,7 +48,7 @@ fn lookup<R, OnHit>(
 impl<'tcx, K: Eq + Hash, V: 'tcx> CacheSelector<'tcx, V> for DefaultCacheSelector<K> {
     type Cache = DefaultCache<K, V>
     where
-        V: Clone;
+        V: Copy;
     type ArenaCache = ArenaCache<'tcx, K, V>;
 }
 
@@ -72,7 +65,7 @@ fn default() -> Self {
     }
 }
 
-impl<K: Eq + Hash, V: Clone + Debug> QueryStorage for DefaultCache<K, V> {
+impl<K: Eq + Hash, V: Copy + Debug> QueryStorage for DefaultCache<K, V> {
     type Value = V;
     type Stored = V;
 
@@ -86,15 +79,12 @@ fn store_nocache(&self, value: Self::Value) -> Self::Stored {
 impl<K, V> QueryCache for DefaultCache<K, V>
 where
     K: Eq + Hash + Clone + Debug,
-    V: Clone + Debug,
+    V: Copy + Debug,
 {
     type Key = K;
 
     #[inline(always)]
-    fn lookup<R, OnHit>(&self, key: &K, on_hit: OnHit) -> Result<R, ()>
-    where
-        OnHit: FnOnce(&V, DepNodeIndex) -> R,
-    {
+    fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> {
         let key_hash = sharded::make_hash(key);
         #[cfg(parallel_compiler)]
         let lock = self.cache.get_shard_by_hash(key_hash).lock();
@@ -102,12 +92,7 @@ fn lookup<R, OnHit>(&self, key: &K, on_hit: OnHit) -> Result<R, ()>
         let lock = self.cache.lock();
         let result = lock.raw_entry().from_key_hashed_nocheck(key_hash, key);
 
-        if let Some((_, value)) = result {
-            let hit_result = on_hit(&value.0, value.1);
-            Ok(hit_result)
-        } else {
-            Err(())
-        }
+        if let Some((_, value)) = result { Some(*value) } else { None }
     }
 
     #[inline]
@@ -176,10 +161,7 @@ impl<'tcx, K, V: 'tcx> QueryCache for ArenaCache<'tcx, K, V>
     type Key = K;
 
     #[inline(always)]
-    fn lookup<R, OnHit>(&self, key: &K, on_hit: OnHit) -> Result<R, ()>
-    where
-        OnHit: FnOnce(&&'tcx V, DepNodeIndex) -> R,
-    {
+    fn lookup(&self, key: &K) -> Option<(&'tcx V, DepNodeIndex)> {
         let key_hash = sharded::make_hash(key);
         #[cfg(parallel_compiler)]
         let lock = self.cache.get_shard_by_hash(key_hash).lock();
@@ -187,12 +169,7 @@ fn lookup<R, OnHit>(&self, key: &K, on_hit: OnHit) -> Result<R, ()>
         let lock = self.cache.lock();
         let result = lock.raw_entry().from_key_hashed_nocheck(key_hash, key);
 
-        if let Some((_, value)) = result {
-            let hit_result = on_hit(&&value.0, value.1);
-            Ok(hit_result)
-        } else {
-            Err(())
-        }
+        if let Some((_, value)) = result { Some((&value.0, value.1)) } else { None }
     }
 
     #[inline]
@@ -234,7 +211,7 @@ fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
 impl<'tcx, K: Idx, V: 'tcx> CacheSelector<'tcx, V> for VecCacheSelector<K> {
     type Cache = VecCache<K, V>
     where
-        V: Clone;
+        V: Copy;
     type ArenaCache = VecArenaCache<'tcx, K, V>;
 }
 
@@ -251,7 +228,7 @@ fn default() -> Self {
     }
 }
 
-impl<K: Eq + Idx, V: Clone + Debug> QueryStorage for VecCache<K, V> {
+impl<K: Eq + Idx, V: Copy + Debug> QueryStorage for VecCache<K, V> {
     type Value = V;
     type Stored = V;
 
@@ -265,25 +242,17 @@ fn store_nocache(&self, value: Self::Value) -> Self::Stored {
 impl<K, V> QueryCache for VecCache<K, V>
 where
     K: Eq + Idx + Clone + Debug,
-    V: Clone + Debug,
+    V: Copy + Debug,
 {
     type Key = K;
 
     #[inline(always)]
-    fn lookup<R, OnHit>(&self, key: &K, on_hit: OnHit) -> Result<R, ()>
-    where
-        OnHit: FnOnce(&V, DepNodeIndex) -> R,
-    {
+    fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> {
         #[cfg(parallel_compiler)]
         let lock = self.cache.get_shard_by_hash(key.index() as u64).lock();
         #[cfg(not(parallel_compiler))]
         let lock = self.cache.lock();
-        if let Some(Some(value)) = lock.get(*key) {
-            let hit_result = on_hit(&value.0, value.1);
-            Ok(hit_result)
-        } else {
-            Err(())
-        }
+        if let Some(Some(value)) = lock.get(*key) { Some(*value) } else { None }
     }
 
     #[inline]
@@ -357,20 +326,12 @@ impl<'tcx, K, V: 'tcx> QueryCache for VecArenaCache<'tcx, K, V>
     type Key = K;
 
     #[inline(always)]
-    fn lookup<R, OnHit>(&self, key: &K, on_hit: OnHit) -> Result<R, ()>
-    where
-        OnHit: FnOnce(&&'tcx V, DepNodeIndex) -> R,
-    {
+    fn lookup(&self, key: &K) -> Option<(&'tcx V, DepNodeIndex)> {
         #[cfg(parallel_compiler)]
         let lock = self.cache.get_shard_by_hash(key.index() as u64).lock();
         #[cfg(not(parallel_compiler))]
         let lock = self.cache.lock();
-        if let Some(Some(value)) = lock.get(*key) {
-            let hit_result = on_hit(&&value.0, value.1);
-            Ok(hit_result)
-        } else {
-            Err(())
-        }
+        if let Some(Some(value)) = lock.get(*key) { Some((&value.0, value.1)) } else { None }
     }
 
     #[inline]
index 8c0330e438de4724711816ed47742d1e5537aee1..a28e45a5c086dc66805730ad804b22df8dfb38fa 100644 (file)
@@ -21,7 +21,7 @@ pub trait QueryConfig<Qcx: QueryContext> {
 
     type Key: DepNodeParams<Qcx::DepContext> + Eq + Hash + Clone + Debug;
     type Value: Debug;
-    type Stored: Debug + Clone + std::borrow::Borrow<Self::Value>;
+    type Stored: Debug + Copy + std::borrow::Borrow<Self::Value>;
 
     type Cache: QueryCache<Key = Self::Key, Stored = Self::Stored, Value = Self::Value>;
 
index b3b939eae88dce04c1e1efa8bb3a6bcc19a9910a..ffc413d15f52b0528d7c294b554be089940df5fc 100644 (file)
@@ -130,7 +130,7 @@ fn mk_cycle<Qcx, V, R, D: DepKind>(
 where
     Qcx: QueryContext + crate::query::HasDepContext<DepKind = D>,
     V: std::fmt::Debug + Value<Qcx::DepContext, Qcx::DepKind>,
-    R: Clone,
+    R: Copy,
 {
     let error = report_cycle(qcx.dep_context().sess(), &cycle_error);
     let value = handle_cycle_error(*qcx.dep_context(), &cycle_error, error, handler);
@@ -339,25 +339,21 @@ enum TryGetJob<'tcx, K, D>
 /// which will be used if the query is not in the cache and we need
 /// to compute it.
 #[inline]
-pub fn try_get_cached<Tcx, C, R, OnHit>(
-    tcx: Tcx,
-    cache: &C,
-    key: &C::Key,
-    // `on_hit` can be called while holding a lock to the query cache
-    on_hit: OnHit,
-) -> Result<R, ()>
+pub fn try_get_cached<Tcx, C>(tcx: Tcx, cache: &C, key: &C::Key) -> Option<C::Stored>
 where
     C: QueryCache,
     Tcx: DepContext,
-    OnHit: FnOnce(&C::Stored) -> R,
 {
-    cache.lookup(&key, |value, index| {
-        if std::intrinsics::unlikely(tcx.profiler().enabled()) {
-            tcx.profiler().query_cache_hit(index.into());
+    match cache.lookup(&key) {
+        Some((value, index)) => {
+            if std::intrinsics::unlikely(tcx.profiler().enabled()) {
+                tcx.profiler().query_cache_hit(index.into());
+            }
+            tcx.dep_graph().read_index(index);
+            Some(value)
         }
-        tcx.dep_graph().read_index(index);
-        on_hit(value)
-    })
+        None => None,
+    }
 }
 
 fn try_execute_query<Q, Qcx>(
@@ -379,17 +375,25 @@ fn try_execute_query<Q, Qcx>(
             if Q::FEEDABLE {
                 // We may have put a value inside the cache from inside the execution.
                 // Verify that it has the same hash as what we have now, to ensure consistency.
-                let _ = cache.lookup(&key, |cached_result, _| {
+                if let Some((cached_result, _)) = cache.lookup(&key) {
                     let hasher = Q::HASH_RESULT.expect("feedable forbids no_hash");
 
-                    let old_hash = qcx.dep_context().with_stable_hashing_context(|mut hcx| hasher(&mut hcx, cached_result.borrow()));
-                    let new_hash = qcx.dep_context().with_stable_hashing_context(|mut hcx| hasher(&mut hcx, &result));
+                    let old_hash = qcx.dep_context().with_stable_hashing_context(|mut hcx| {
+                        hasher(&mut hcx, cached_result.borrow())
+                    });
+                    let new_hash = qcx
+                        .dep_context()
+                        .with_stable_hashing_context(|mut hcx| hasher(&mut hcx, &result));
                     debug_assert_eq!(
-                        old_hash, new_hash,
+                        old_hash,
+                        new_hash,
                         "Computed query value for {:?}({:?}) is inconsistent with fed value,\ncomputed={:#?}\nfed={:#?}",
-                        Q::DEP_KIND, key, result, cached_result,
+                        Q::DEP_KIND,
+                        key,
+                        result,
+                        cached_result,
                     );
-                });
+                }
             }
             let result = job.complete(cache, result, dep_node_index);
             (result, Some(dep_node_index))
@@ -400,9 +404,9 @@ fn try_execute_query<Q, Qcx>(
         }
         #[cfg(parallel_compiler)]
         TryGetJob::JobCompleted(query_blocked_prof_timer) => {
-            let (v, index) = cache
-                .lookup(&key, |value, index| (value.clone(), index))
-                .unwrap_or_else(|_| panic!("value must be in cache after waiting"));
+            let Some((v, index)) = cache.lookup(&key) else {
+                panic!("value must be in cache after waiting")
+            };
 
             if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) {
                 qcx.dep_context().profiler().query_cache_hit(index.into());
@@ -771,15 +775,11 @@ pub fn force_query<Q, Qcx, D>(qcx: Qcx, key: Q::Key, dep_node: DepNode<Qcx::DepK
     // We may be concurrently trying both execute and force a query.
     // Ensure that only one of them runs the query.
     let cache = Q::query_cache(qcx);
-    let cached = cache.lookup(&key, |_, index| {
+    if let Some((_, index)) = cache.lookup(&key) {
         if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) {
             qcx.dep_context().profiler().query_cache_hit(index.into());
         }
-    });
-
-    match cached {
-        Ok(()) => return,
-        Err(()) => {}
+        return;
     }
 
     let state = Q::query_state(qcx);
index 87dfccdef2f10af64e15d34525aad68f19a52b0d..55178250472ef94bc08d45ba429ea02f7f83458b 100644 (file)
@@ -84,7 +84,11 @@ pub fn record_type_size<S: ToString>(
         // Sort variants so the largest ones are shown first. A stable sort is
         // used here so that source code order is preserved for all variants
         // that have the same size.
-        variants.sort_by(|info1, info2| info2.size.cmp(&info1.size));
+        // Except for Generators, whose variants are already sorted according to
+        // their yield points in `variant_info_for_generator`.
+        if kind != DataTypeKind::Generator {
+            variants.sort_by(|info1, info2| info2.size.cmp(&info1.size));
+        }
         let info = TypeSizeInfo {
             kind,
             type_description: type_desc.to_string(),
index dbd419c1406f867c09644875e70b9231e8b355fd..8a0176f6391743adb6a17ccf30a3fc49223b92b3 100644 (file)
@@ -3,15 +3,7 @@
 pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
 use crate::config::Input;
 use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath};
-use crate::errors::{
-    BranchProtectionRequiresAArch64, CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers,
-    LinkerPluginToWindowsNotSupported, NotCircumventFeature, OptimisationFuelExhausted,
-    ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist, SanitizerCfiEnabled,
-    SanitizerNotSupported, SanitizersNotSupported, SkippingConstChecks,
-    SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget,
-    TargetRequiresUnwindTables, UnleashedFeatureHelp, UnstableVirtualFunctionElimination,
-    UnsupportedDwarfVersion,
-};
+use crate::errors;
 use crate::parse::{add_feature_diagnostics, ParseSess};
 use crate::search_paths::{PathKind, SearchPath};
 use crate::{filesearch, lint};
@@ -246,15 +238,15 @@ fn check_miri_unleashed_features(&self) {
         if !unleashed_features.is_empty() {
             let mut must_err = false;
             // Create a diagnostic pointing at where things got unleashed.
-            self.emit_warning(SkippingConstChecks {
+            self.emit_warning(errors::SkippingConstChecks {
                 unleashed_features: unleashed_features
                     .iter()
                     .map(|(span, gate)| {
                         gate.map(|gate| {
                             must_err = true;
-                            UnleashedFeatureHelp::Named { span: *span, gate }
+                            errors::UnleashedFeatureHelp::Named { span: *span, gate }
                         })
-                        .unwrap_or(UnleashedFeatureHelp::Unnamed { span: *span })
+                        .unwrap_or(errors::UnleashedFeatureHelp::Unnamed { span: *span })
                     })
                     .collect(),
             });
@@ -262,7 +254,7 @@ fn check_miri_unleashed_features(&self) {
             // If we should err, make sure we did.
             if must_err && self.has_errors().is_none() {
                 // We have skipped a feature gate, and not run into other errors... reject.
-                self.emit_err(NotCircumventFeature);
+                self.emit_err(errors::NotCircumventFeature);
             }
         }
     }
@@ -901,7 +893,7 @@ pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -
                         // We only call `msg` in case we can actually emit warnings.
                         // Otherwise, this could cause a `delay_good_path_bug` to
                         // trigger (issue #79546).
-                        self.emit_warning(OptimisationFuelExhausted { msg: msg() });
+                        self.emit_warning(errors::OptimisationFuelExhausted { msg: msg() });
                     }
                     fuel.out_of_fuel = true;
                 } else if fuel.remaining > 0 {
@@ -1502,28 +1494,28 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         && sess.opts.cg.prefer_dynamic
         && sess.target.is_like_windows
     {
-        sess.emit_err(LinkerPluginToWindowsNotSupported);
+        sess.emit_err(errors::LinkerPluginToWindowsNotSupported);
     }
 
     // Make sure that any given profiling data actually exists so LLVM can't
     // decide to silently skip PGO.
     if let Some(ref path) = sess.opts.cg.profile_use {
         if !path.exists() {
-            sess.emit_err(ProfileUseFileDoesNotExist { path });
+            sess.emit_err(errors::ProfileUseFileDoesNotExist { path });
         }
     }
 
     // Do the same for sample profile data.
     if let Some(ref path) = sess.opts.unstable_opts.profile_sample_use {
         if !path.exists() {
-            sess.emit_err(ProfileSampleUseFileDoesNotExist { path });
+            sess.emit_err(errors::ProfileSampleUseFileDoesNotExist { path });
         }
     }
 
     // Unwind tables cannot be disabled if the target requires them.
     if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables {
         if sess.target.requires_uwtable && !include_uwtables {
-            sess.emit_err(TargetRequiresUnwindTables);
+            sess.emit_err(errors::TargetRequiresUnwindTables);
         }
     }
 
@@ -1533,16 +1525,18 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     match unsupported_sanitizers.into_iter().count() {
         0 => {}
         1 => {
-            sess.emit_err(SanitizerNotSupported { us: unsupported_sanitizers.to_string() });
+            sess.emit_err(errors::SanitizerNotSupported { us: unsupported_sanitizers.to_string() });
         }
         _ => {
-            sess.emit_err(SanitizersNotSupported { us: unsupported_sanitizers.to_string() });
+            sess.emit_err(errors::SanitizersNotSupported {
+                us: unsupported_sanitizers.to_string(),
+            });
         }
     }
     // Cannot mix and match sanitizers.
     let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter();
     if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
-        sess.emit_err(CannotMixAndMatchSanitizers {
+        sess.emit_err(errors::CannotMixAndMatchSanitizers {
             first: first.to_string(),
             second: second.to_string(),
         });
@@ -1550,22 +1544,22 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
 
     // Cannot enable crt-static with sanitizers on Linux
     if sess.crt_static(None) && !sess.opts.unstable_opts.sanitizer.is_empty() {
-        sess.emit_err(CannotEnableCrtStaticLinux);
+        sess.emit_err(errors::CannotEnableCrtStaticLinux);
     }
 
     // LLVM CFI and VFE both require LTO.
     if sess.lto() != config::Lto::Fat {
         if sess.is_sanitizer_cfi_enabled() {
-            sess.emit_err(SanitizerCfiEnabled);
+            sess.emit_err(errors::SanitizerCfiEnabled);
         }
         if sess.opts.unstable_opts.virtual_function_elimination {
-            sess.emit_err(UnstableVirtualFunctionElimination);
+            sess.emit_err(errors::UnstableVirtualFunctionElimination);
         }
     }
 
     // LLVM CFI and KCFI are mutually exclusive
     if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() {
-        sess.emit_err(CannotMixAndMatchSanitizers {
+        sess.emit_err(errors::CannotMixAndMatchSanitizers {
             first: "cfi".to_string(),
             second: "kcfi".to_string(),
         });
@@ -1573,7 +1567,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
 
     if sess.opts.unstable_opts.stack_protector != StackProtector::None {
         if !sess.target.options.supports_stack_protector {
-            sess.emit_warning(StackProtectorNotSupportedForTarget {
+            sess.emit_warning(errors::StackProtectorNotSupportedForTarget {
                 stack_protector: sess.opts.unstable_opts.stack_protector,
                 target_triple: &sess.opts.target_triple,
             });
@@ -1581,19 +1575,19 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     }
 
     if sess.opts.unstable_opts.branch_protection.is_some() && sess.target.arch != "aarch64" {
-        sess.emit_err(BranchProtectionRequiresAArch64);
+        sess.emit_err(errors::BranchProtectionRequiresAArch64);
     }
 
     if let Some(dwarf_version) = sess.opts.unstable_opts.dwarf_version {
         if dwarf_version > 5 {
-            sess.emit_err(UnsupportedDwarfVersion { dwarf_version });
+            sess.emit_err(errors::UnsupportedDwarfVersion { dwarf_version });
         }
     }
 
     if !sess.target.options.supported_split_debuginfo.contains(&sess.split_debuginfo())
         && !sess.opts.unstable_opts.unstable_options
     {
-        sess.emit_err(SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() });
+        sess.emit_err(errors::SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() });
     }
 }
 
index 7c5e1427d1ed72e9e7a8f45ad2c2e70cb8eef90e..cdda052f529067a27f4c82d49c04bef4a8d7df6e 100644 (file)
@@ -119,6 +119,12 @@ pub fn new(stable_crate_id: StableCrateId, local_hash: u64) -> DefPathHash {
     }
 }
 
+impl Default for DefPathHash {
+    fn default() -> Self {
+        DefPathHash(Fingerprint::ZERO)
+    }
+}
+
 impl Borrow<Fingerprint> for DefPathHash {
     #[inline]
     fn borrow(&self) -> &Fingerprint {
index 90d879976c260cb33d84020b09a0ff33c9423d71..3f863038efb3769f6b0968ce25ebc55331c8f2f1 100644 (file)
@@ -16,7 +16,6 @@ rustc_errors = { path = "../rustc_errors" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 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" }
index 36170b3788a7a7b0cc5d1cf21badbbf48ae0f261..e4725c0a1b7326895344eeb0a31dcefe967ca4e7 100644 (file)
@@ -24,7 +24,8 @@
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::Obligation;
 use rustc_middle::infer::canonical::Certainty as OldCertainty;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::ty::{
     CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, ToPredicate, TypeOutlivesPredicate,
 };
@@ -72,8 +73,7 @@ fn from(obligation: Obligation<'tcx, P>) -> Goal<'tcx, P> {
         Goal { param_env: obligation.param_env, predicate: obligation.predicate }
     }
 }
-
-#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable)]
+#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
 pub struct Response<'tcx> {
     pub var_values: CanonicalVarValues<'tcx>,
     /// Additional constraints returned by this query.
@@ -121,14 +121,6 @@ pub enum MaybeCause {
     Overflow,
 }
 
-/// Additional constraints returned on success.
-#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable, Default)]
-pub struct ExternalConstraints<'tcx> {
-    // FIXME: implement this.
-    regions: (),
-    opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>,
-}
-
 type CanonicalGoal<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, Goal<'tcx, T>>;
 type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>;
 /// The result of evaluating a canonical query.
@@ -218,15 +210,14 @@ fn evaluate_canonical_goal(
                 EvalCtxt { infcx, var_values, search_graph, in_projection_eq_hack: false };
             let result = ecx.compute_goal(goal);
 
-            // FIXME: `Response` should be `Copy`
-            if search_graph.try_finalize_goal(tcx, canonical_goal, result.clone()) {
+            if search_graph.try_finalize_goal(tcx, canonical_goal, result) {
                 return result;
             }
         }
     }
 
     fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> {
-        let external_constraints = take_external_constraints(self.infcx)?;
+        let external_constraints = compute_external_query_constraints(self.infcx)?;
 
         Ok(self.infcx.canonicalize_response(Response {
             var_values: self.var_values,
@@ -461,18 +452,18 @@ fn evaluate_all_and_make_canonical_response(
 }
 
 #[instrument(level = "debug", skip(infcx), ret)]
-fn take_external_constraints<'tcx>(
+fn compute_external_query_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 {
+    Ok(infcx.tcx.intern_external_constraints(ExternalConstraintsData {
         // FIXME: Now that's definitely wrong :)
         //
         // Should also do the leak check here I think
         regions: drop(region_obligations),
         opaque_types,
-    })
+    }))
 }
 
 fn instantiate_canonical_query_response<'tcx>(
@@ -492,7 +483,10 @@ fn instantiate_canonical_query_response<'tcx>(
                     Certainty::Yes => OldCertainty::Proven,
                     Certainty::Maybe(_) => OldCertainty::Ambiguous,
                 },
-                opaque_types: resp.external_constraints.opaque_types,
+                // FIXME: This to_owned makes me sad, but we should eventually impl
+                // `instantiate_query_response_and_region_obligations` separately
+                // instead of piggybacking off of the old implementation.
+                opaque_types: resp.external_constraints.opaque_types.to_owned(),
                 value: resp.certainty,
             }),
         ) else { bug!(); };
@@ -510,7 +504,10 @@ pub(super) fn response_no_constraints<'tcx>(
         variables: goal.variables,
         value: Response {
             var_values: CanonicalVarValues::make_identity(tcx, goal.variables),
-            external_constraints: Default::default(),
+            // FIXME: maybe we should store the "no response" version in tcx, like
+            // we do for tcx.types and stuff.
+            external_constraints: tcx
+                .intern_external_constraints(ExternalConstraintsData::default()),
             certainty,
         },
     })
index 80a388b8498b9784677f17ee2fdf7bb39f0a0761..86b13c05f76aa16a7706601514b6dd1ea5327ce9 100644 (file)
@@ -95,8 +95,7 @@ pub(super) fn depth(&self, entry_index: EntryIndex) -> StackDepth {
     }
 
     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()
+        self.entries[entry_index].response
     }
 }
 
index 87dbf7c3fd699b2649d36acb122d49de5a99676c..91da690a00056d58fc9fcfec0746d832c01de720 100644 (file)
@@ -679,6 +679,7 @@ fn suggest_restricting_param_bound(
                         &param_name,
                         &constraint,
                         Some(trait_pred.def_id()),
+                        None,
                     ) {
                         return;
                     }
@@ -1087,6 +1088,7 @@ fn suggest_add_clone_to_arg(
                     param.name.as_str(),
                     "Clone",
                     Some(clone_trait),
+                    None,
                 );
             }
             err.span_suggestion_verbose(
index 0a4136dc1cfe5f508c252874cf7be7fe43cbd259..94d9eb8f587a70ebbd9383cccdab5c516cdbca04 100644 (file)
@@ -1190,6 +1190,7 @@ fn confirm_const_destruct_candidate(
                 ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
                     derived,
                     impl_def_id,
+                    impl_def_predicate_index: None,
                     span: obligation.cause.span,
                 }))
             });
index ad7d479896fd04eddacaaa4e3f58fce3a50eaff7..0c6b2406bbdafb0cd0e547a405e72cc988e9a494 100644 (file)
@@ -2608,11 +2608,12 @@ fn impl_or_trait_obligations(
         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 {
+        for (index, (predicate, span)) in predicates.into_iter().enumerate() {
             let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
                 ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
                     derived,
                     impl_def_id: def_id,
+                    impl_def_predicate_index: Some(index),
                     span,
                 }))
             });
index a432498abcca4001a5498a150796de84300a4644..eff6fb26dd4c503f8091b224acc24e9f3be40597 100644 (file)
@@ -5,7 +5,6 @@ edition = "2021"
 
 [dependencies]
 tracing = "0.1"
-rustc_attr = { path = "../rustc_attr" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_hir = { path = "../rustc_hir" }
index 1c74aeca5ab1fae38a6e6234c6ad7b40b292078b..ad5527f5a778b89bb11ba49c9f95c23f3b307491 100644 (file)
@@ -254,15 +254,18 @@ fn adjust_for_rust_scalar<'tcx>(
         if let Some(kind) = pointee.safe {
             attrs.pointee_align = Some(pointee.align);
 
-            // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable
-            // for the entire duration of the function as they can be deallocated
-            // at any time. Same for shared mutable references. If LLVM had a
-            // way to say "dereferenceable on entry" we could use it here.
+            // `Box` are not necessarily dereferenceable for the entire duration of the function as
+            // they can be deallocated at any time. Same for non-frozen shared references (see
+            // <https://github.com/rust-lang/rust/pull/98017>), and for mutable references to
+            // potentially self-referential types (see
+            // <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>). If LLVM had a way
+            // to say "dereferenceable on entry" we could use it here.
             attrs.pointee_size = match kind {
-                PointerKind::UniqueBorrowed
-                | PointerKind::UniqueBorrowedPinned
-                | PointerKind::Frozen => pointee.size,
-                PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
+                PointerKind::Box { .. }
+                | PointerKind::SharedRef { frozen: false }
+                | PointerKind::MutableRef { unpin: false } => Size::ZERO,
+                PointerKind::SharedRef { frozen: true }
+                | PointerKind::MutableRef { unpin: true } => pointee.size,
             };
 
             // The aliasing rules for `Box<T>` are still not decided, but currently we emit
@@ -275,18 +278,16 @@ fn adjust_for_rust_scalar<'tcx>(
             // versions at all anymore. We still support turning it off using -Zmutable-noalias.
             let noalias_mut_ref = cx.tcx.sess.opts.unstable_opts.mutable_noalias;
 
-            // `&mut` pointer parameters never alias other parameters,
-            // or mutable global data
+            // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as both
+            // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on memory
+            // dependencies rather than pointer equality. However this only applies to arguments,
+            // not return values.
             //
-            // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
-            // and can be marked as both `readonly` and `noalias`, as
-            // LLVM's definition of `noalias` is based solely on memory
-            // dependencies rather than pointer equality
+            // `&mut T` and `Box<T>` where `T: Unpin` are unique and hence `noalias`.
             let no_alias = match kind {
-                PointerKind::SharedMutable | PointerKind::UniqueBorrowedPinned => false,
-                PointerKind::UniqueBorrowed => noalias_mut_ref,
-                PointerKind::UniqueOwned => noalias_for_box,
-                PointerKind::Frozen => true,
+                PointerKind::SharedRef { frozen } => frozen,
+                PointerKind::MutableRef { unpin } => unpin && noalias_mut_ref,
+                PointerKind::Box { unpin } => unpin && noalias_for_box,
             };
             // We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics
             // (see <https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745>).
@@ -294,7 +295,7 @@ fn adjust_for_rust_scalar<'tcx>(
                 attrs.set(ArgAttribute::NoAlias);
             }
 
-            if kind == PointerKind::Frozen && !is_return {
+            if matches!(kind, PointerKind::SharedRef { frozen: true }) && !is_return {
                 attrs.set(ArgAttribute::ReadOnly);
             }
         }
index 424b52309d3af8bcc58bf1a1164d9a4f18c0839c..a6e0f13f69830350d8c55611c635841edc461212 100644 (file)
@@ -22,14 +22,17 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
         hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
             impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()),
         ),
-        hir::ItemKind::TraitAlias(..) => &[],
         _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
     }
 }
 
 fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
-    let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
-    ty::AssocItems::new(items)
+    if tcx.is_trait_alias(def_id) {
+        ty::AssocItems::new(Vec::new())
+    } else {
+        let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
+        ty::AssocItems::new(items)
+    }
 }
 
 fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId, DefId> {
index 93c9c675c9a6be2cfb88826ca27b7c5e35e13b0c..2aeb255c1641c61b6329110582aa8bd8ea06808d 100644 (file)
@@ -970,7 +970,7 @@ fn variant_info_for_generator<'tcx>(
         })
         .collect();
 
-    let variant_infos: Vec<_> = generator
+    let mut variant_infos: Vec<_> = generator
         .variant_fields
         .iter_enumerated()
         .map(|(variant_idx, variant_def)| {
@@ -1033,6 +1033,15 @@ fn variant_info_for_generator<'tcx>(
             }
         })
         .collect();
+
+    // The first three variants are hardcoded to be `UNRESUMED`, `RETURNED` and `POISONED`.
+    // We will move the `RETURNED` and `POISONED` elements to the end so we
+    // are left with a sorting order according to the generators yield points:
+    // First `Unresumed`, then the `SuspendN` followed by `Returned` and `Panicked` (POISONED).
+    let end_states = variant_infos.drain(1..=2);
+    let end_states: Vec<_> = end_states.collect();
+    variant_infos.extend(end_states);
+
     (
         variant_infos,
         match tag_encoding {
index d5de457a82ce98ece71342abaa4d3ff6f0ee2225..4aa958878d4b304678644cd7eb50c5d92812371a 100644 (file)
@@ -220,7 +220,8 @@ pub struct TypeFlags: u32 {
                                           // which is different from how types/const are freshened.
                                           | TypeFlags::HAS_TY_FRESH.bits
                                           | TypeFlags::HAS_CT_FRESH.bits
-                                          | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
+                                          | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits
+                                          | TypeFlags::HAS_RE_ERASED.bits;
 
         /// Does this have `Projection`?
         const HAS_TY_PROJECTION           = 1 << 10;
index b75ae996e4853b46219e4495f4ae08f1d5168fb6..f290e5baf9dd3c21ccdd9c4f979daea388d8e459 100644 (file)
@@ -22,7 +22,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use crate::const_closure::ConstFnMutClosure;
 use crate::marker::Destruct;
 
 use self::Ordering::*;
@@ -1291,17 +1290,7 @@ pub const fn max_by_key<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(v1: T, v2: T
     F: ~const Destruct,
     K: ~const Destruct,
 {
-    const fn imp<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(
-        f: &mut F,
-        (v1, v2): (&T, &T),
-    ) -> Ordering
-    where
-        T: ~const Destruct,
-        K: ~const Destruct,
-    {
-        f(v1).cmp(&f(v2))
-    }
-    max_by(v1, v2, ConstFnMutClosure::new(&mut f, imp))
+    max_by(v1, v2, const |v1, v2| f(v1).cmp(&f(v2)))
 }
 
 // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
diff --git a/library/core/src/const_closure.rs b/library/core/src/const_closure.rs
deleted file mode 100644 (file)
index 97900a4..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-use crate::marker::Destruct;
-use crate::marker::Tuple;
-
-/// Struct representing a closure with mutably borrowed data.
-///
-/// Example:
-/// ```no_build
-/// #![feature(const_mut_refs)]
-/// use crate::const_closure::ConstFnMutClosure;
-/// const fn imp(state: &mut i32, (arg,): (i32,)) -> i32 {
-///   *state += arg;
-///   *state
-/// }
-/// let mut i = 5;
-/// let mut cl = ConstFnMutClosure::new(&mut i, imp);
-///
-/// assert!(7 == cl(2));
-/// assert!(8 == cl(1));
-/// ```
-pub(crate) struct ConstFnMutClosure<CapturedData, Function> {
-    /// The Data captured by the Closure.
-    /// Must be either a (mutable) reference or a tuple of (mutable) references.
-    pub data: CapturedData,
-    /// The Function of the Closure, must be: Fn(CapturedData, ClosureArgs) -> ClosureReturn
-    pub func: Function,
-}
-impl<'a, CapturedData: ?Sized, Function> ConstFnMutClosure<&'a mut CapturedData, Function> {
-    /// Function for creating a new closure.
-    ///
-    /// `data` is the a mutable borrow of data that is captured from the environment.
-    /// If you want Data to be a tuple of mutable Borrows, the struct must be constructed manually.
-    ///
-    /// `func` is the function of the closure, it gets the data and a tuple of the arguments closure
-    ///   and return the return value of the closure.
-    pub(crate) const fn new<ClosureArguments, ClosureReturnValue>(
-        data: &'a mut CapturedData,
-        func: Function,
-    ) -> Self
-    where
-        Function: ~const Fn(&mut CapturedData, ClosureArguments) -> ClosureReturnValue,
-    {
-        Self { data, func }
-    }
-}
-
-macro_rules! impl_fn_mut_tuple {
-    ($($var:ident)*) => {
-        #[allow(unused_parens)]
-        impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
-            FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
-        where
-            Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue+ ~const Destruct,
-        {
-            type Output = ClosureReturnValue;
-
-            extern "rust-call" fn call_once(mut self, args: ClosureArguments) -> Self::Output {
-            self.call_mut(args)
-            }
-        }
-        #[allow(unused_parens)]
-        impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
-            FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
-        where
-            Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue,
-        {
-            extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output {
-                #[allow(non_snake_case)]
-                let ($($var),*) = &mut self.data;
-                (self.func)(($($var),*), args)
-            }
-        }
-    };
-}
-impl_fn_mut_tuple!(A);
-impl_fn_mut_tuple!(A B);
-impl_fn_mut_tuple!(A B C);
-impl_fn_mut_tuple!(A B C D);
-impl_fn_mut_tuple!(A B C D E);
index 5e4211058aa6f2b8bcd0182ef18fc340f54c771d..af786609757b1325d85c166a3a382929bba74634 100644 (file)
@@ -1,5 +1,4 @@
 use crate::array;
-use crate::const_closure::ConstFnMutClosure;
 use crate::iter::{ByRefSized, FusedIterator, Iterator, TrustedRandomAccessNoCoerce};
 use crate::mem::{self, MaybeUninit};
 use crate::ops::{ControlFlow, NeverShortCircuit, Try};
@@ -189,13 +188,12 @@ impl<I, const N: usize> SpecFold for ArrayChunks<I, N>
     I: Iterator,
 {
     #[inline]
-    default fn fold<B, F>(mut self, init: B, mut f: F) -> B
+    default fn fold<B, F>(mut self, init: B, f: F) -> B
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> B,
     {
-        let fold = ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp);
-        self.try_fold(init, fold).0
+        self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0
     }
 }
 
index 1945e402ff50ed8e4875cebd8f7bb7c98202f9fa..477e7117c3ea125973252685d8bded87ab93686f 100644 (file)
@@ -1,7 +1,4 @@
-use crate::{
-    const_closure::ConstFnMutClosure,
-    ops::{NeverShortCircuit, Try},
-};
+use crate::ops::{NeverShortCircuit, Try};
 
 /// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics.
 ///
@@ -39,13 +36,12 @@ fn nth(&mut self, n: usize) -> Option<Self::Item> {
     }
 
     #[inline]
-    fn fold<B, F>(self, init: B, mut f: F) -> B
+    fn fold<B, F>(self, init: B, f: F) -> B
     where
         F: FnMut(B, Self::Item) -> B,
     {
         // `fold` needs ownership, so this can't forward directly.
-        I::try_fold(self.0, init, ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp))
-            .0
+        I::try_fold(self.0, init, NeverShortCircuit::wrap_mut_2(f)).0
     }
 
     #[inline]
@@ -76,17 +72,12 @@ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
     }
 
     #[inline]
-    fn rfold<B, F>(self, init: B, mut f: F) -> B
+    fn rfold<B, F>(self, init: B, f: F) -> B
     where
         F: FnMut(B, Self::Item) -> B,
     {
         // `rfold` needs ownership, so this can't forward directly.
-        I::try_rfold(
-            self.0,
-            init,
-            ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp),
-        )
-        .0
+        I::try_rfold(self.0, init, NeverShortCircuit::wrap_mut_2(f)).0
     }
 
     #[inline]
index bb35d50b4bfda2a7c39313d8faa753f8758e713d..00f57fbcc6162abd5e591edc85766a7711153225 100644 (file)
@@ -362,15 +362,13 @@ macro_rules! impl_fold_via_try_fold {
     };
     (@internal $fold:ident -> $try_fold:ident) => {
         #[inline]
-        fn $fold<AAA, FFF>(mut self, init: AAA, mut fold: FFF) -> AAA
+        fn $fold<AAA, FFF>(mut self, init: AAA, fold: FFF) -> AAA
         where
             FFF: FnMut(AAA, Self::Item) -> AAA,
         {
-            use crate::const_closure::ConstFnMutClosure;
             use crate::ops::NeverShortCircuit;
 
-            let fold = ConstFnMutClosure::new(&mut fold, NeverShortCircuit::wrap_mut_2_imp);
-            self.$try_fold(init, fold).0
+            self.$try_fold(init, NeverShortCircuit::wrap_mut_2(fold)).0
         }
     };
 }
index 8961ef4ab48167583f683d66808005c8e0279365..dc0702c467a4ea1d3c69d2ce21504c114a91fc13 100644 (file)
@@ -376,8 +376,6 @@ pub mod assert_matches {
 mod tuple;
 mod unit;
 
-mod const_closure;
-
 #[stable(feature = "core_primitive", since = "1.43.0")]
 pub mod primitive;
 
index 1c97c46862833a2e2c351c69649f782ac18a6b97..dcc0835ecd6d2c6b22a777e96eac9ce925eff8d0 100644 (file)
@@ -18,7 +18,7 @@ macro_rules! uint_impl {
         pub const MIN: Self = 0;
 
         /// The largest value that can be represented by this integer type
-        #[doc = concat!("(2<sup>", $BITS, "</sup> &minus; 1", $bound_condition, ")")]
+        #[doc = concat!("(2<sup>", $BITS, "</sup> &minus; 1", $bound_condition, ").")]
         ///
         /// # Examples
         ///
index cc13db5c9565beca6844381a896532759c654fae..0c7ee9630c6ee560127731249ef633dd2823578f 100644 (file)
@@ -86,7 +86,8 @@ pub trait Add<Rhs = Self> {
     /// ```
     /// assert_eq!(12 + 1, 13);
     /// ```
-    #[must_use]
+    #[must_use = "this returns the result of the operation, without modifying the original"]
+    #[rustc_diagnostic_item = "add"]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn add(self, rhs: Rhs) -> Self::Output;
 }
@@ -195,7 +196,8 @@ pub trait Sub<Rhs = Self> {
     /// ```
     /// assert_eq!(12 - 1, 11);
     /// ```
-    #[must_use]
+    #[must_use = "this returns the result of the operation, without modifying the original"]
+    #[rustc_diagnostic_item = "sub"]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn sub(self, rhs: Rhs) -> Self::Output;
 }
@@ -325,7 +327,8 @@ pub trait Mul<Rhs = Self> {
     /// ```
     /// assert_eq!(12 * 2, 24);
     /// ```
-    #[must_use]
+    #[must_use = "this returns the result of the operation, without modifying the original"]
+    #[rustc_diagnostic_item = "mul"]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn mul(self, rhs: Rhs) -> Self::Output;
 }
@@ -459,7 +462,8 @@ pub trait Div<Rhs = Self> {
     /// ```
     /// assert_eq!(12 / 2, 6);
     /// ```
-    #[must_use]
+    #[must_use = "this returns the result of the operation, without modifying the original"]
+    #[rustc_diagnostic_item = "div"]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn div(self, rhs: Rhs) -> Self::Output;
 }
@@ -562,7 +566,8 @@ pub trait Rem<Rhs = Self> {
     /// ```
     /// assert_eq!(12 % 10, 2);
     /// ```
-    #[must_use]
+    #[must_use = "this returns the result of the operation, without modifying the original"]
+    #[rustc_diagnostic_item = "rem"]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn rem(self, rhs: Rhs) -> Self::Output;
 }
@@ -678,7 +683,8 @@ pub trait Neg {
     /// let x: i32 = 12;
     /// assert_eq!(-x, -12);
     /// ```
-    #[must_use]
+    #[must_use = "this returns the result of the operation, without modifying the original"]
+    #[rustc_diagnostic_item = "neg"]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn neg(self) -> Self::Output;
 }
index 84a69046807c4b3fb314afd6b96ed46e0dcf7bc4..9108fc63045250d5369d2d63d4fc6581cc18ad9e 100644 (file)
@@ -379,13 +379,18 @@ pub trait Residual<O> {
 pub(crate) struct NeverShortCircuit<T>(pub T);
 
 impl<T> NeverShortCircuit<T> {
-    /// Implementation for building `ConstFnMutClosure` for wrapping the output of a ~const FnMut in a `NeverShortCircuit`.
     #[inline]
-    pub const fn wrap_mut_2_imp<A, B, F: ~const FnMut(A, B) -> T>(
-        f: &mut F,
-        (a, b): (A, B),
-    ) -> NeverShortCircuit<T> {
-        NeverShortCircuit(f(a, b))
+    pub fn wrap_mut_2<A, B>(
+        mut f: impl ~const FnMut(A, B) -> T,
+    ) -> impl ~const FnMut(A, B) -> Self {
+        cfg_if! {
+            if #[cfg(bootstrap)] {
+                #[allow(unused_parens)]
+                (const move |a, b| NeverShortCircuit(f(a, b)))
+            } else {
+                const move |a, b| NeverShortCircuit(f(a, b))
+            }
+        }
     }
 }
 
index c43b728022d2fa60ab35b41f249c33410d3afef0..5d5e95590344ad44672d7c57295cb052f2b32d1f 100644 (file)
@@ -943,7 +943,7 @@ pub const fn unwrap_or_default(self) -> T
     // Transforming contained values
     /////////////////////////////////////////////////////////////////////////
 
-    /// Maps an `Option<T>` to `Option<U>` by applying a function to a contained value.
+    /// Maps an `Option<T>` to `Option<U>` by applying a function to a contained value (if `Some`) or returns `None` (if `None`).
     ///
     /// # Examples
     ///
@@ -955,8 +955,10 @@ pub const fn unwrap_or_default(self) -> T
     /// let maybe_some_string = Some(String::from("Hello, World!"));
     /// // `Option::map` takes self *by value*, consuming `maybe_some_string`
     /// let maybe_some_len = maybe_some_string.map(|s| s.len());
-    ///
     /// assert_eq!(maybe_some_len, Some(13));
+    ///
+    /// let x: Option<&str> = None;
+    /// assert_eq!(x.map(|s| s.len()), None);
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
index 818721062d7f702aeba8df4096d55fbc6456427e..1d14efc7523b42a9c86e4f23b555e45771df316a 100644 (file)
@@ -928,8 +928,8 @@ pub fn fetch_not(&self, order: Ordering) -> bool {
     /// ```
     #[inline]
     #[unstable(feature = "atomic_mut_ptr", reason = "recently added", issue = "66893")]
-    pub fn as_mut_ptr(&self) -> *mut bool {
-        self.v.get() as *mut bool
+    pub const fn as_mut_ptr(&self) -> *mut bool {
+        self.v.get().cast()
     }
 
     /// Fetches the value, and applies a function to it that returns an optional
@@ -1803,7 +1803,7 @@ pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T {
     ///
     /// ```ignore (extern-declaration)
     /// #![feature(atomic_mut_ptr)]
-    //// use std::sync::atomic::AtomicPtr;
+    /// use std::sync::atomic::AtomicPtr;
     ///
     /// extern "C" {
     ///     fn my_atomic_op(arg: *mut *mut u32);
@@ -1819,7 +1819,7 @@ pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T {
     /// ```
     #[inline]
     #[unstable(feature = "atomic_mut_ptr", reason = "recently added", issue = "66893")]
-    pub fn as_mut_ptr(&self) -> *mut *mut T {
+    pub const fn as_mut_ptr(&self) -> *mut *mut T {
         self.p.get()
     }
 }
@@ -2727,7 +2727,7 @@ pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
             #[unstable(feature = "atomic_mut_ptr",
                    reason = "recently added",
                    issue = "66893")]
-            pub fn as_mut_ptr(&self) -> *mut $int_type {
+            pub const fn as_mut_ptr(&self) -> *mut $int_type {
                 self.v.get()
             }
         }
index df490358827e7ae9c8fd777450dc776a19f66b10..742c4cc7c5539d9a4b5175e70d7b3371f3917b64 100644 (file)
@@ -238,7 +238,7 @@ pub fn new() -> HashMap<K, V, RandomState> {
     ///
     /// The hash map will be able to hold at least `capacity` elements without
     /// reallocating. This method is allowed to allocate for more elements than
-    /// `capacity`. If `capacity` is 0, the hash set will not allocate.
+    /// `capacity`. If `capacity` is 0, the hash map will not allocate.
     ///
     /// # Examples
     ///
index 4e30076246314edb50cdf017b1f1aa00878a3d12..6b1f0cba82dfc877cddfba31465fcb28af5798ad 100644 (file)
@@ -69,8 +69,8 @@ pub fn ceil(self) -> f32 {
         unsafe { intrinsics::ceilf32(self) }
     }
 
-    /// Returns the nearest integer to `self`. Round half-way cases away from
-    /// `0.0`.
+    /// Returns the nearest integer to `self`. If a value is half-way between two
+    /// integers, round away from `0.0`.
     ///
     /// # Examples
     ///
index ec67fdad4f726f50ac11d503701fef61ab8664b5..16359766b510d865e6c8846fe5a6c966fa488429 100644 (file)
@@ -69,8 +69,8 @@ pub fn ceil(self) -> f64 {
         unsafe { intrinsics::ceilf64(self) }
     }
 
-    /// Returns the nearest integer to `self`. Round half-way cases away from
-    /// `0.0`.
+    /// Returns the nearest integer to `self`. If a value is half-way between two
+    /// integers, round away from `0.0`.
     ///
     /// # Examples
     ///
index 3cabf24492eaf26216e811a85b158d25abbc136f..324d698eaeb1d129a772f7bb31db616aee342b62 100644 (file)
@@ -88,12 +88,23 @@ fn from(_: alloc::ffi::NulError) -> Error {
 // doesn't accidentally get printed.
 #[cfg_attr(test, derive(Debug))]
 enum ErrorData<C> {
-    Os(i32),
+    Os(RawOsError),
     Simple(ErrorKind),
     SimpleMessage(&'static SimpleMessage),
     Custom(C),
 }
 
+/// The type of raw OS error codes returned by [`Error::raw_os_error`].
+///
+/// This is an [`i32`] on all currently supported platforms, but platforms
+/// added in the future (such as UEFI) may use a different primitive type like
+/// [`usize`]. Use `as`or [`into`] conversions where applicable to ensure maximum
+/// portability.
+///
+/// [`into`]: Into::into
+#[unstable(feature = "raw_os_error_ty", issue = "none")]
+pub type RawOsError = i32;
+
 // `#[repr(align(4))]` is probably redundant, it should have that value or
 // higher already. We include it just because repr_bitpacked.rs's encoding
 // requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the
@@ -579,7 +590,7 @@ pub(crate) const fn from_static_message(msg: &'static SimpleMessage) -> Error {
     #[must_use]
     #[inline]
     pub fn last_os_error() -> Error {
-        Error::from_raw_os_error(sys::os::errno() as i32)
+        Error::from_raw_os_error(sys::os::errno())
     }
 
     /// Creates a new instance of an [`Error`] from a particular OS error code.
@@ -610,7 +621,7 @@ pub fn last_os_error() -> Error {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
     #[inline]
-    pub fn from_raw_os_error(code: i32) -> Error {
+    pub fn from_raw_os_error(code: RawOsError) -> Error {
         Error { repr: Repr::new_os(code) }
     }
 
@@ -646,7 +657,7 @@ pub fn from_raw_os_error(code: i32) -> Error {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
     #[inline]
-    pub fn raw_os_error(&self) -> Option<i32> {
+    pub fn raw_os_error(&self) -> Option<RawOsError> {
         match self.repr.data() {
             ErrorData::Os(i) => Some(i),
             ErrorData::Custom(..) => None,
index 3581484050dd1a4e506574b46d99ce609c5ed996..f94f88bac417ef1d1c9086263bda11a6ba5ce382 100644 (file)
 //! to use a pointer type to store something that may hold an integer, some of
 //! the time.
 
-use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
+use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
 use alloc::boxed::Box;
 use core::marker::PhantomData;
 use core::mem::{align_of, size_of};
@@ -172,7 +172,7 @@ pub(super) fn new_custom(b: Box<Custom>) -> Self {
     }
 
     #[inline]
-    pub(super) fn new_os(code: i32) -> Self {
+    pub(super) fn new_os(code: RawOsError) -> Self {
         let utagged = ((code as usize) << 32) | TAG_OS;
         // Safety: `TAG_OS` is not zero, so the result of the `|` is not 0.
         let res = Self(unsafe { NonNull::new_unchecked(ptr::invalid_mut(utagged)) }, PhantomData);
@@ -250,7 +250,7 @@ unsafe fn decode_repr<C, F>(ptr: NonNull<()>, make_custom: F) -> ErrorData<C>
     let bits = ptr.as_ptr().addr();
     match bits & TAG_MASK {
         TAG_OS => {
-            let code = ((bits as i64) >> 32) as i32;
+            let code = ((bits as i64) >> 32) as RawOsError;
             ErrorData::Os(code)
         }
         TAG_SIMPLE => {
@@ -374,6 +374,9 @@ macro_rules! static_assert {
 static_assert!(align_of::<SimpleMessage>() >= TAG_MASK + 1);
 static_assert!(align_of::<Custom>() >= TAG_MASK + 1);
 
+// `RawOsError` must be an alias for `i32`.
+const _: fn(RawOsError) -> i32 = |os| os;
+
 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);
index d6ad55b99f5c0aef5abe2d413084b1e2a84d0033..093fde33757eb6e8cfe694b7ef36b07004319a38 100644 (file)
@@ -2,7 +2,7 @@
 //! non-64bit targets, where the packed 64 bit representation wouldn't work, and
 //! would have no benefit.
 
-use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
+use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
 use alloc::boxed::Box;
 
 type Inner = ErrorData<Box<Custom>>;
@@ -18,7 +18,7 @@ pub(super) fn new_custom(b: Box<Custom>) -> Self {
         Self(Inner::Custom(b))
     }
     #[inline]
-    pub(super) fn new_os(code: i32) -> Self {
+    pub(super) fn new_os(code: RawOsError) -> Self {
         Self(Inner::Os(code))
     }
     #[inline]
index 9aea62a5b940c553cfb011ecb322f7ff7a5a9af0..36d52aef03cb7b211f382af9136817c0b2f667b9 100644 (file)
@@ -71,7 +71,7 @@ fn test_const() {
 
 #[test]
 fn test_os_packing() {
-    for code in -20i32..20i32 {
+    for code in -20..20 {
         let e = Error::from_raw_os_error(code);
         assert_eq!(e.raw_os_error(), Some(code));
         assert_matches!(
index de528e85368cbf5ed6b471b7411f4e3b97b53ca4..5907ba5d5fbf3ab8dd8495cd2619aa25f5b7de09 100644 (file)
 
 #[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
 pub use self::buffered::WriterPanicked;
+#[unstable(feature = "raw_os_error_ty", issue = "none")]
+pub use self::error::RawOsError;
 pub(crate) use self::stdio::attempt_print_to_stderr;
 #[unstable(feature = "internal_output_capture", issue = "none")]
 #[doc(no_inline, hidden)]
index 8dce9e79e16b88aeecae40e1b00219f0cfdb1448..71eee8968e272e66593286e252455c53460c265c 100644 (file)
@@ -4,105 +4,31 @@ This is an in-progress README which is targeted at helping to explain how Rust
 is bootstrapped and in general, some of the technical details of the build
 system.
 
-## Using rustbuild
+Note that this README only covers internal information, not how to use the tool.
+Please check [bootstrapping dev guide][bootstrapping-dev-guide] for further information.
 
-The rustbuild build system has a primary entry point, a top level `x.py` script:
+[bootstrapping-dev-guide]: https://rustc-dev-guide.rust-lang.org/building/bootstrapping.html
 
-```sh
-$ python ./x.py build
-```
-
-Note that if you're on Unix, you should be able to execute the script directly:
-
-```sh
-$ ./x.py build
-```
-
-The script accepts commands, flags, and arguments to determine what to do:
-
-* `build` - a general purpose command for compiling code. Alone, `build` will
-  bootstrap the entire compiler, and otherwise, arguments passed indicate what to
-  build. For example:
-
-  ```
-  # build the whole compiler
-  ./x.py build --stage 2
-
-  # build the stage1 compiler
-  ./x.py build
-
-  # build stage0 libstd
-  ./x.py build --stage 0 library/std
-
-  # build a particular crate in stage0
-  ./x.py build --stage 0 library/test
-  ```
-
-  If files that would normally be rebuilt from stage 0 are dirty, the rebuild can be
-  overridden using `--keep-stage 0`. Using `--keep-stage n` will skip all steps
-  that belong to stage n or earlier:
-
-  ```
-  # build stage 1, keeping old build products for stage 0
-  ./x.py build --keep-stage 0
-  ```
-
-* `test` - a command for executing unit tests. Like the `build` command, this
-  will execute the entire test suite by default, and otherwise, it can be used to
-  select which test suite is run:
-
-  ```
-  # run all unit tests
-  ./x.py test
-
-  # execute tool tests
-  ./x.py test tidy
-
-  # execute the UI test suite
-  ./x.py test tests/ui
-
-  # execute only some tests in the UI test suite
-  ./x.py test tests/ui --test-args substring-of-test-name
-
-  # execute tests in the standard library in stage0
-  ./x.py test --stage 0 library/std
-
-  # execute tests in the core and standard library in stage0,
-  # without running doc tests (thus avoid depending on building the compiler)
-  ./x.py test --stage 0 --no-doc library/core library/std
+## Introduction
 
-  # execute all doc tests
-  ./x.py test src/doc
-  ```
+The build system defers most of the complicated logic managing invocations
+of rustc and rustdoc to Cargo itself. However, moving through various stages
+and copying artifacts is still necessary for it to do. Each time rustbuild
+is invoked, it will iterate through the list of predefined steps and execute
+each serially in turn if it matches the paths passed or is a default rule.
+For each step rustbuild relies on the step internally being incremental and
+parallel. Note, though, that the `-j` parameter to rustbuild gets forwarded
+to appropriate test harnesses and such.
 
-* `doc` - a command for building documentation. Like above, can take arguments
-  for what to document.
-
-## Configuring rustbuild
-
-rustbuild offers a TOML-based configuration system with a `config.toml`
-file. An example of this configuration can be found at `config.toml.example`,
-and the configuration file can also be passed as `--config path/to/config.toml`
-if the build system is being invoked manually (via the python script).
-
-You can generate a config.toml using `./configure` options if you want to automate creating the file without having to edit it.
-
-Finally, rustbuild makes use of the [cc-rs crate] which has [its own
-method][env-vars] of configuring C compilers and C flags via environment
-variables.
-
-[cc-rs crate]: https://github.com/alexcrichton/cc-rs
-[env-vars]: https://github.com/alexcrichton/cc-rs#external-configuration-via-environment-variables
-
-## Build stages
+## Build phases
 
 The rustbuild build system goes through a few phases to actually build the
 compiler. What actually happens when you invoke rustbuild is:
 
-1. The entry point script, `x.py` is run. This script is
-   responsible for downloading the stage0 compiler/Cargo binaries, and it then
-   compiles the build system itself (this folder). Finally, it then invokes the
-   actual `bootstrap` binary build system.
+1. The entry point script(`x` for unix like systems, `x.ps1` for windows systems,
+   `x.py` cross-platform) is run. This script is responsible for downloading the stage0
+   compiler/Cargo binaries, and it then compiles the build system itself (this folder).
+   Finally, it then invokes the actual `bootstrap` binary build system.
 2. In Rust, `bootstrap` will slurp up all configuration, perform a number of
    sanity checks (whether compilers exist, for example), and then start building the
    stage0 artifacts.
@@ -115,24 +41,6 @@ compiler. What actually happens when you invoke rustbuild is:
 The goal of each stage is to (a) leverage Cargo as much as possible and failing
 that (b) leverage Rust as much as possible!
 
-## Incremental builds
-
-You can configure rustbuild to use incremental compilation with the
-`--incremental` flag:
-
-```sh
-$ ./x.py build --incremental
-```
-
-The `--incremental` flag will store incremental compilation artifacts
-in `build/<host>/stage0-incremental`. Note that we only use incremental
-compilation for the stage0 -> stage1 compilation -- this is because
-the stage1 compiler is changing, and we don't try to cache and reuse
-incremental artifacts across different versions of the compiler.
-
-You can always drop the `--incremental` to build as normal (but you
-will still be using the local nightly as your bootstrap).
-
 ## Directory Layout
 
 This build system houses all output under the `build` directory, which looks
@@ -236,63 +144,31 @@ build/
     # system will link (using hard links) output from stageN-{std,rustc} into
     # each of these directories.
     #
-    # In theory, there is no extra build output in these directories.
+    # In theory these are working rustc sysroot directories, meaning there is
+    # no extra build output in these directories.
     stage1/
     stage2/
     stage3/
 ```
 
-## Cargo projects
-
-The current build is unfortunately not quite as simple as `cargo build` in a
-directory, but rather the compiler is split into three different Cargo projects:
-
-* `library/std` - the standard library
-* `library/test` - testing support, depends on libstd
-* `compiler/rustc` - the actual compiler itself
-
-Each "project" has a corresponding Cargo.lock file with all dependencies, and
-this means that building the compiler involves running Cargo three times. The
-structure here serves two goals:
-
-1. Facilitating dependencies coming from crates.io. These dependencies don't
-   depend on `std`, so libstd is a separate project compiled ahead of time
-   before the actual compiler builds.
-2. Splitting "host artifacts" from "target artifacts". That is, when building
-   code for an arbitrary target, you don't need the entire compiler, but you'll
-   end up needing libraries like libtest that depend on std but also want to use
-   crates.io dependencies. Hence, libtest is split out as its own project that
-   is sequenced after `std` but before `rustc`. This project is built for all
-   targets.
-
-There is some loss in build parallelism here because libtest can be compiled in
-parallel with a number of rustc artifacts, but in theory, the loss isn't too bad!
-
-## Build tools
-
-We've actually got quite a few tools that we use in the compiler's build system
-and for testing. To organize these, each tool is a project in `src/tools` with a
-corresponding `Cargo.toml`. All tools are compiled with Cargo (currently having
-independent `Cargo.lock` files) and do not currently explicitly depend on the
-compiler or standard library. Compiling each tool is sequenced after the
-appropriate libstd/libtest/librustc compile above.
-
 ## Extending rustbuild
 
-So, you'd like to add a feature to the rustbuild build system or just fix a bug.
-Great! One of the major motivational factors for moving away from `make` is that
-Rust is in theory much easier to read, modify, and write. If you find anything
-excessively confusing, please open an issue on this, and we'll try to get it
-documented or simplified, pronto.
+When you use the bootstrap system, you'll call it through the entry point script
+(`x`, `x.ps1`, or `x.py`). However, most of the code lives in `src/bootstrap`.
+`bootstrap` has a difficult problem: it is written in Rust, but yet it is run
+before the Rust compiler is built! To work around this, there are two components
+of bootstrap: the main one written in rust, and `bootstrap.py`. `bootstrap.py`
+is what gets run by entry point script. It takes care of downloading the `stage0`
+compiler, which will then build the bootstrap binary written in Rust.
 
-First up, you'll probably want to read over the documentation above, as that'll
-give you a high level overview of what rustbuild is doing. You also probably
-want to play around a bit yourself by just getting it up and running before you
-dive too much into the actual build system itself.
+Because there are two separate codebases behind `x.py`, they need to
+be kept in sync. In particular, both `bootstrap.py` and the bootstrap binary
+parse `config.toml` and read the same command line arguments. `bootstrap.py`
+keeps these in sync by setting various environment variables, and the
+programs sometimes have to add arguments that are explicitly ignored, to be
+read by the other.
 
-After that, each module in rustbuild should have enough documentation to keep
-you up and running. Some general areas that you may be interested in modifying
-are:
+Some general areas that you may be interested in modifying are:
 
 * Adding a new build tool? Take a look at `bootstrap/tool.rs` for examples of
   other tools.
@@ -320,8 +196,9 @@ A 'major change' includes
 Changes that do not affect contributors to the compiler or users
 building rustc from source don't need an update to `VERSION`.
 
-If you have any questions, feel free to reach out on the `#t-infra` channel in
-the [Rust Zulip server][rust-zulip] or ask on internals.rust-lang.org. When
-you encounter bugs, please file issues on the rust-lang/rust issue tracker.
+If you have any questions, feel free to reach out on the `#t-infra/bootstrap` channel
+at [Rust Bootstrap Zulip server][rust-bootstrap-zulip]. When you encounter bugs,
+please file issues on the [Rust issue tracker][rust-issue-tracker].
 
-[rust-zulip]: https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra
+[rust-bootstrap-zulip]: https://rust-lang.zulipchat.com/#narrow/stream/t-infra.2Fbootstrap
+[rust-issue-tracker]: https://github.com/rust-lang/rust/issues
index 267aa3278d8ffcb0e6e4b17c276eca7bf6760afe..f4abdf1cc57589e51c8c8aec36e07e48dfdecac9 100644 (file)
 //!   crates.io and Cargo.
 //! * A standard interface to build across all platforms, including MSVC
 //!
-//! ## Architecture
-//!
-//! The build system defers most of the complicated logic managing invocations
-//! of rustc and rustdoc to Cargo itself. However, moving through various stages
-//! and copying artifacts is still necessary for it to do. Each time rustbuild
-//! is invoked, it will iterate through the list of predefined steps and execute
-//! each serially in turn if it matches the paths passed or is a default rule.
-//! For each step rustbuild relies on the step internally being incremental and
-//! parallel. Note, though, that the `-j` parameter to rustbuild gets forwarded
-//! to appropriate test harnesses and such.
-//!
-//! Most of the "meaty" steps that matter are backed by Cargo, which does indeed
-//! have its own parallelism and incremental management. Later steps, like
-//! tests, aren't incremental and simply run the entire suite currently.
-//! However, compiletest itself tries to avoid running tests when the artifacts
-//! that are involved (mainly the compiler) haven't changed.
-//!
-//! When you execute `x.py build`, the steps executed are:
-//!
-//! * First, the python script is run. This will automatically download the
-//!   stage0 rustc and cargo according to `src/stage0.json`, or use the cached
-//!   versions if they're available. These are then used to compile rustbuild
-//!   itself (using Cargo). Finally, control is then transferred to rustbuild.
-//!
-//! * Rustbuild takes over, performs sanity checks, probes the environment,
-//!   reads configuration, and starts executing steps as it reads the command
-//!   line arguments (paths) or going through the default rules.
-//!
-//!   The build output will be something like the following:
-//!
-//!   Building stage0 std artifacts
-//!   Copying stage0 std
-//!   Building stage0 test artifacts
-//!   Copying stage0 test
-//!   Building stage0 compiler artifacts
-//!   Copying stage0 rustc
-//!   Assembling stage1 compiler
-//!   Building stage1 std artifacts
-//!   Copying stage1 std
-//!   Building stage1 test artifacts
-//!   Copying stage1 test
-//!   Building stage1 compiler artifacts
-//!   Copying stage1 rustc
-//!   Assembling stage2 compiler
-//!   Uplifting stage1 std
-//!   Uplifting stage1 test
-//!   Uplifting stage1 rustc
-//!
-//! Let's disect that a little:
-//!
-//! ## Building stage0 {std,test,compiler} artifacts
-//!
-//! These steps use the provided (downloaded, usually) compiler to compile the
-//! local Rust source into libraries we can use.
-//!
-//! ## Copying stage0 {std,test,rustc}
-//!
-//! This copies the build output from Cargo into
-//! `build/$HOST/stage0-sysroot/lib/rustlib/$ARCH/lib`. FIXME: this step's
-//! documentation should be expanded -- the information already here may be
-//! incorrect.
-//!
-//! ## Assembling stage1 compiler
-//!
-//! This copies the libraries we built in "building stage0 ... artifacts" into
-//! the stage1 compiler's lib directory. These are the host libraries that the
-//! compiler itself uses to run. These aren't actually used by artifacts the new
-//! compiler generates. This step also copies the rustc and rustdoc binaries we
-//! generated into build/$HOST/stage/bin.
-//!
-//! The stage1/bin/rustc is a fully functional compiler, but it doesn't yet have
-//! any libraries to link built binaries or libraries to. The next 3 steps will
-//! provide those libraries for it; they are mostly equivalent to constructing
-//! the stage1/bin compiler so we don't go through them individually.
-//!
-//! ## Uplifting stage1 {std,test,rustc}
-//!
-//! This step copies the libraries from the stage1 compiler sysroot into the
-//! stage2 compiler. This is done to avoid rebuilding the compiler; libraries
-//! we'd build in this step should be identical (in function, if not necessarily
-//! identical on disk) so there's no need to recompile the compiler again. Note
-//! that if you want to, you can enable the full-bootstrap option to change this
-//! behavior.
-//!
-//! Each step is driven by a separate Cargo project and rustbuild orchestrates
-//! copying files between steps and otherwise preparing for Cargo to run.
-//!
 //! ## Further information
 //!
 //! More documentation can be found in each respective module below, and you can
index 6078e39ac9d3b8af5a7214921d91edff4c238385..8a0c532cfb02fe5c29132adb7cb6a2757728696a 100644 (file)
@@ -1114,9 +1114,6 @@ fn run(self, builder: &Builder<'_>) {
             cmd.arg("--bless");
         }
 
-        builder.info("tidy check");
-        try_run(builder, &mut cmd);
-
         if builder.config.channel == "dev" || builder.config.channel == "nightly" {
             builder.info("fmt check");
             if builder.initial_rustfmt().is_none() {
@@ -1134,6 +1131,11 @@ fn run(self, builder: &Builder<'_>) {
             }
             crate::format::format(&builder, !builder.config.cmd.bless(), &[]);
         }
+
+        builder.info("tidy check");
+        try_run(builder, &mut cmd);
+
+        builder.ensure(ExpandYamlAnchors {});
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
index c0a1341ebca5c3b24347e2705368444df8a77d73..3c128c0ca251b514142c020fbc7c6409ee843a06 100644 (file)
@@ -307,8 +307,6 @@ jobs:
           - name: x86_64-gnu-tools
             <<: *job-linux-xl
             tidy: false
-            env:
-              CI_ONLY_WHEN_SUBMODULES_CHANGED: 1
 
   auto:
     permissions:
index 85d772253808ae5a6cdfe74ad6b336f214aec102..48127166ad0809b644ba4b533b042588ab0eec7a 100755 (executable)
@@ -1,46 +1,11 @@
 #!/bin/bash
-# Set the SKIP_JOB environment variable if this job is supposed to only run
-# when submodules are updated and they were not. The following time consuming
-# tasks will be skipped when the environment variable is present.
+# Set the SKIP_JOB environment variable if this job is not supposed to run on the current builder.
 
 set -euo pipefail
 IFS=$'\n\t'
 
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
-if [[ -n "${CI_ONLY_WHEN_SUBMODULES_CHANGED-}" ]]; then
-    git fetch "https://github.com/$GITHUB_REPOSITORY" "$GITHUB_BASE_REF"
-    BASE_COMMIT="$(git merge-base FETCH_HEAD HEAD)"
-
-    echo "Searching for toolstate changes between $BASE_COMMIT and $(git rev-parse HEAD)"
-
-    if git diff "$BASE_COMMIT" | grep --quiet "^index .* 160000"; then
-        # Submodules pseudo-files inside git have the 160000 permissions, so when
-        # those files are present in the diff a submodule was updated.
-        echo "Submodules were updated"
-    elif ! (git diff --quiet "$BASE_COMMIT" -- \
-             src/tools/clippy src/tools/rustfmt src/tools/miri \
-             library/std/src/sys); then
-        # There is not an easy blanket search for subtrees. For now, manually list
-        # the subtrees.
-        # Also run this when the platform-specific parts of std change, in case
-        # that breaks Miri.
-        echo "Tool subtrees were updated"
-    elif ! (git diff --quiet "$BASE_COMMIT" -- \
-             tests/rustdoc-gui \
-             src/librustdoc \
-             src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile \
-             src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version \
-             src/tools/rustdoc-gui); then
-        # There was a change in either rustdoc or in its GUI tests.
-        echo "Rustdoc was updated"
-    else
-        echo "Not executing this job since no submodules nor subtrees were updated"
-        ciCommandSetEnv SKIP_JOB 1
-        exit 0
-    fi
-fi
-
 if [[ -n "${CI_ONLY_WHEN_CHANNEL-}" ]]; then
     if [[ "${CI_ONLY_WHEN_CHANNEL}" = "$(cat src/ci/channel)" ]]; then
         echo "The channel is the expected one"
index c373edfcf46a26ffefb1f21142f54afb0af4c198..662c9e36694c652d31f932e668054c5ec35c846f 100644 (file)
@@ -15,10 +15,9 @@ import sys
 import time
 import traceback
 import urllib.request
-from collections import OrderedDict
 from io import StringIO
 from pathlib import Path
-from typing import Callable, Dict, Iterable, List, Optional, Union
+from typing import Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union
 
 PGO_HOST = os.environ["PGO_HOST"]
 
@@ -204,48 +203,105 @@ class WindowsPipeline(Pipeline):
         return False
 
 
+def get_timestamp() -> float:
+    return time.time()
+
+
+Duration = float
+TimerSection = Union[Duration, "Timer"]
+
+
+def iterate_sections(section: TimerSection, name: str, level: int = 0) -> Iterator[Tuple[int, str, Duration]]:
+    """
+    Hierarchically iterate the sections of a timer, in a depth-first order.
+    """
+    if isinstance(section, Duration):
+        yield (level, name, section)
+    elif isinstance(section, Timer):
+        yield (level, name, section.total_duration())
+        for (child_name, child_section) in section.sections:
+            yield from iterate_sections(child_section, child_name, level=level + 1)
+    else:
+        assert False
+
+
 class Timer:
-    def __init__(self):
-        # We want this dictionary to be ordered by insertion.
-        # We use `OrderedDict` for compatibility with older Python versions.
-        self.stages = OrderedDict()
+    def __init__(self, parent_names: Tuple[str, ...] = ()):
+        self.sections: List[Tuple[str, TimerSection]] = []
+        self.section_active = False
+        self.parent_names = parent_names
 
     @contextlib.contextmanager
-    def stage(self, name: str):
-        assert name not in self.stages
+    def section(self, name: str) -> "Timer":
+        assert not self.section_active
+        self.section_active = True
 
-        start = time.time()
+        start = get_timestamp()
         exc = None
+
+        child_timer = Timer(parent_names=self.parent_names + (name, ))
+        full_name = " > ".join(child_timer.parent_names)
         try:
-            LOGGER.info(f"Stage `{name}` starts")
-            yield
+            LOGGER.info(f"Section `{full_name}` starts")
+            yield child_timer
         except BaseException as exception:
             exc = exception
             raise
         finally:
-            end = time.time()
+            end = get_timestamp()
             duration = end - start
-            self.stages[name] = duration
+
+            if child_timer.has_children():
+                self.sections.append((name, child_timer))
+            else:
+                self.sections.append((name, duration))
             if exc is None:
-                LOGGER.info(f"Stage `{name}` ended: OK ({duration:.2f}s)")
+                LOGGER.info(f"Section `{full_name}` ended: OK ({duration:.2f}s)")
+            else:
+                LOGGER.info(f"Section `{full_name}` ended: FAIL ({duration:.2f}s)")
+            self.section_active = False
+
+    def total_duration(self) -> Duration:
+        duration = 0
+        for (_, section) in self.sections:
+            if isinstance(section, Duration):
+                duration += section
             else:
-                LOGGER.info(f"Stage `{name}` ended: FAIL ({duration:.2f}s)")
+                duration += section.total_duration()
+        return duration
+
+    def has_children(self) -> bool:
+        return len(self.sections) > 0
 
     def print_stats(self):
-        total_duration = sum(self.stages.values())
+        rows = []
+        for (child_name, child_section) in self.sections:
+            for (level, name, duration) in iterate_sections(child_section, child_name, level=0):
+                label = f"{' ' * level}{name}:"
+                rows.append((label, duration))
 
-        # 57 is the width of the whole table
-        divider = "-" * 57
+        # Empty row
+        rows.append(("", ""))
+
+        total_duration_label = "Total duration:"
+        total_duration = self.total_duration()
+        rows.append((total_duration_label, humantime(total_duration)))
+
+        space_after_label = 2
+        max_label_length = max(16, max(len(label) for (label, _) in rows)) + space_after_label
+
+        table_width = max_label_length + 23
+        divider = "-" * table_width
 
         with StringIO() as output:
             print(divider, file=output)
-            for (name, duration) in self.stages.items():
-                pct = (duration / total_duration) * 100
-                name_str = f"{name}:"
-                print(f"{name_str:<34} {duration:>12.2f}s ({pct:>5.2f}%)", file=output)
-
-            total_duration_label = "Total duration:"
-            print(f"{total_duration_label:<34} {total_duration:>12.2f}s", file=output)
+            for (label, duration) in rows:
+                if isinstance(duration, Duration):
+                    pct = (duration / total_duration) * 100
+                    value = f"{duration:>12.2f}s ({pct:>5.2f}%)"
+                else:
+                    value = f"{duration:>{len(total_duration_label) + 7}}"
+                print(f"{label:<{max_label_length}} {value}", file=output)
             print(divider, file=output, end="")
             LOGGER.info(f"Timer results\n{output.getvalue()}")
 
@@ -265,6 +321,21 @@ def change_cwd(dir: Path):
         os.chdir(cwd)
 
 
+def humantime(time_s: float) -> str:
+    hours = time_s // 3600
+    time_s = time_s % 3600
+    minutes = time_s // 60
+    seconds = time_s % 60
+
+    result = ""
+    if hours > 0:
+        result += f"{int(hours)}h "
+    if minutes > 0:
+        result += f"{int(minutes)}m "
+    result += f"{round(seconds)}s"
+    return result
+
+
 def move_path(src: Path, dst: Path):
     LOGGER.info(f"Moving `{src}` to `{dst}`")
     shutil.move(src, dst)
@@ -585,15 +656,16 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L
     pipeline.build_rustc_perf()
 
     # Stage 1: Build rustc + PGO instrumented LLVM
-    with timer.stage("Build rustc (LLVM PGO)"):
-        build_rustc(pipeline, args=[
-            "--llvm-profile-generate"
-        ], env=dict(
-            LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p")
-        ))
+    with timer.section("Stage 1 (LLVM PGO)") as stage1:
+        with stage1.section("Build rustc and LLVM"):
+            build_rustc(pipeline, args=[
+                "--llvm-profile-generate"
+            ], env=dict(
+                LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p")
+            ))
 
-    with timer.stage("Gather profiles (LLVM PGO)"):
-        gather_llvm_profiles(pipeline)
+        with stage1.section("Gather profiles"):
+            gather_llvm_profiles(pipeline)
 
     clear_llvm_files(pipeline)
     final_build_args += [
@@ -602,14 +674,15 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L
     ]
 
     # Stage 2: Build PGO instrumented rustc + LLVM
-    with timer.stage("Build rustc (rustc PGO)"):
-        build_rustc(pipeline, args=[
-            "--rust-profile-generate",
-            pipeline.rustc_profile_dir_root()
-        ])
+    with timer.section("Stage 2 (rustc PGO)") as stage2:
+        with stage2.section("Build rustc and LLVM"):
+            build_rustc(pipeline, args=[
+                "--rust-profile-generate",
+                pipeline.rustc_profile_dir_root()
+            ])
 
-    with timer.stage("Gather profiles (rustc PGO)"):
-        gather_rustc_profiles(pipeline)
+        with stage2.section("Gather profiles"):
+            gather_rustc_profiles(pipeline)
 
     clear_llvm_files(pipeline)
     final_build_args += [
@@ -619,14 +692,15 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L
 
     # Stage 3: Build rustc + BOLT instrumented LLVM
     if pipeline.supports_bolt():
-        with timer.stage("Build rustc (LLVM BOLT)"):
-            build_rustc(pipeline, args=[
-                "--llvm-profile-use",
-                pipeline.llvm_profile_merged_file(),
-                "--llvm-bolt-profile-generate",
-            ])
-        with timer.stage("Gather profiles (LLVM BOLT)"):
-            gather_llvm_bolt_profiles(pipeline)
+        with timer.section("Stage 3 (LLVM BOLT)") as stage3:
+            with stage3.section("Build rustc and LLVM"):
+                build_rustc(pipeline, args=[
+                    "--llvm-profile-use",
+                    pipeline.llvm_profile_merged_file(),
+                    "--llvm-bolt-profile-generate",
+                ])
+            with stage3.section("Gather profiles"):
+                gather_llvm_bolt_profiles(pipeline)
 
         clear_llvm_files(pipeline)
         final_build_args += [
@@ -635,7 +709,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L
         ]
 
     # Stage 4: Build PGO optimized rustc + PGO/BOLT optimized LLVM
-    with timer.stage("Final build"):
+    with timer.section("Stage 4 (final build)"):
         cmd(final_build_args)
 
 
index 372350403e28151158e7fb99e309614af90bd960..cea6033ede208f7ce091ba1f800aa1c151f9ce19 100644 (file)
@@ -5,3 +5,4 @@ title = "The rustc book"
 
 [output.html]
 git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustc"
+edit-url-template = "https://github.com/rust-lang/rust/edit/master/src/doc/rustc/{path}"
index 7e355b7fccfc4485a5f11e11d10165ce8148f607..1770c121a0e73064d6db671d6bf3b50b10784e5a 100644 (file)
@@ -562,7 +562,7 @@ Supported values for this option are:
 * `v0` — The "v0" mangling scheme. The specific format is not specified at
   this time.
 
-The default if not specified will use a compiler-chosen default which may
+The default, if not specified, will use a compiler-chosen default which may
 change in the future.
 
 [name mangling]: https://en.wikipedia.org/wiki/Name_mangling
index 33404a76835975da4e656f3f8bff6f5952116202..a59cfbea8853e5428f4a4adf1682eea10d7a0fef 100644 (file)
@@ -208,7 +208,7 @@ pub(crate) fn print<'a, 'tcx: 'a>(
                     if f.alternate() {
                         write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
                     } else {
-                        write!(f, ":&nbsp;{}", print_generic_bounds(bounds, cx))?;
+                        write!(f, ": {}", print_generic_bounds(bounds, cx))?;
                     }
                 }
 
@@ -216,7 +216,7 @@ pub(crate) fn print<'a, 'tcx: 'a>(
                     if f.alternate() {
                         write!(f, " = {:#}", ty.print(cx))?;
                     } else {
-                        write!(f, "&nbsp;=&nbsp;{}", ty.print(cx))?;
+                        write!(f, " = {}", ty.print(cx))?;
                     }
                 }
 
@@ -226,14 +226,14 @@ pub(crate) fn print<'a, 'tcx: 'a>(
                 if f.alternate() {
                     write!(f, "const {}: {:#}", self.name, ty.print(cx))?;
                 } else {
-                    write!(f, "const {}:&nbsp;{}", self.name, ty.print(cx))?;
+                    write!(f, "const {}: {}", self.name, ty.print(cx))?;
                 }
 
                 if let Some(default) = default {
                     if f.alternate() {
                         write!(f, " = {:#}", default)?;
                     } else {
-                        write!(f, "&nbsp;=&nbsp;{}", default)?;
+                        write!(f, " = {}", default)?;
                     }
                 }
 
@@ -353,13 +353,17 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
         } else {
             let mut br_with_padding = String::with_capacity(6 * indent + 28);
             br_with_padding.push_str("<br>");
-            for _ in 0..indent + 4 {
-                br_with_padding.push_str("&nbsp;");
+
+            let padding_amout =
+                if ending == Ending::Newline { indent + 4 } else { indent + "fn where ".len() };
+
+            for _ in 0..padding_amout {
+                br_with_padding.push_str(" ");
             }
             let where_preds = where_preds.to_string().replace("<br>", &br_with_padding);
 
             if ending == Ending::Newline {
-                let mut clause = "&nbsp;".repeat(indent.saturating_sub(1));
+                let mut clause = " ".repeat(indent.saturating_sub(1));
                 write!(clause, "<span class=\"where fmt-newline\">where{where_preds},</span>")?;
                 clause
             } else {
@@ -367,8 +371,12 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
                 if indent == 0 {
                     format!("<br><span class=\"where\">where{where_preds}</span>")
                 } else {
+                    // put the first one on the same line as the 'where' keyword
+                    let where_preds = where_preds.replacen(&br_with_padding, " ", 1);
+
                     let mut clause = br_with_padding;
-                    clause.truncate(clause.len() - 4 * "&nbsp;".len());
+                    clause.truncate(clause.len() - "where ".len());
+
                     write!(clause, "<span class=\"where\">where{where_preds}</span>")?;
                     clause
                 }
@@ -1391,8 +1399,8 @@ fn inner_full_print(
 
         let declaration_len = header_len + args_plain.len() + arrow_plain.len();
         let output = if declaration_len > 80 {
-            let full_pad = format!("<br>{}", "&nbsp;".repeat(indent + 4));
-            let close_pad = format!("<br>{}", "&nbsp;".repeat(indent));
+            let full_pad = format!("<br>{}", " ".repeat(indent + 4));
+            let close_pad = format!("<br>{}", " ".repeat(indent));
             format!(
                 "({pad}{args}{close}){arrow}",
                 pad = if self.inputs.values.is_empty() { "" } else { &full_pad },
@@ -1611,7 +1619,7 @@ pub(crate) fn print<'a, 'tcx: 'a>(
                         if f.alternate() {
                             write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
                         } else {
-                            write!(f, ":&nbsp;{}", print_generic_bounds(bounds, cx))?;
+                            write!(f, ": {}", print_generic_bounds(bounds, cx))?;
                         }
                     }
                 }
index 00e3f859bfcb30dd62dd1f1cde00a9ba41a294ea..fb7c34118a4913569671e2d714334ae3ed36b438 100644 (file)
@@ -102,14 +102,14 @@ pub struct Markdown<'a> {
     /// E.g. if `heading_offset: HeadingOffset::H2`, then `# something` renders an `<h2>`.
     pub heading_offset: HeadingOffset,
 }
-/// A tuple struct like `Markdown` that renders the markdown with a table of contents.
-pub(crate) struct MarkdownWithToc<'a>(
-    pub(crate) &'a str,
-    pub(crate) &'a mut IdMap,
-    pub(crate) ErrorCodes,
-    pub(crate) Edition,
-    pub(crate) &'a Option<Playground>,
-);
+/// A struct like `Markdown` that renders the markdown with a table of contents.
+pub(crate) struct MarkdownWithToc<'a> {
+    pub(crate) content: &'a str,
+    pub(crate) ids: &'a mut IdMap,
+    pub(crate) error_codes: ErrorCodes,
+    pub(crate) edition: Edition,
+    pub(crate) playground: &'a Option<Playground>,
+}
 /// A tuple struct like `Markdown` that renders the markdown escaping HTML tags
 /// and includes no paragraph tags.
 pub(crate) struct MarkdownItemInfo<'a>(pub(crate) &'a str, pub(crate) &'a mut IdMap);
@@ -1048,7 +1048,7 @@ pub fn into_string(self) -> String {
 
 impl MarkdownWithToc<'_> {
     pub(crate) fn into_string(self) -> String {
-        let MarkdownWithToc(md, ids, codes, edition, playground) = self;
+        let MarkdownWithToc { content: md, ids, error_codes: codes, edition, playground } = self;
 
         let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
 
index bd7548003ad3b0cb1cd25a26dd8895d6f49cf3b8..c2d24e514845e0ba1aafe7cf379dd4a23c035141 100644 (file)
@@ -645,6 +645,10 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
             if count_consts != 0 && count_methods != 0 {
                 w.write_str("\n");
             }
+
+            if !required_methods.is_empty() {
+                write!(w, "    // Required method{}\n", pluralize(required_methods.len()));
+            }
             for (pos, m) in required_methods.iter().enumerate() {
                 render_assoc_item(
                     w,
@@ -663,6 +667,10 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
             if !required_methods.is_empty() && !provided_methods.is_empty() {
                 w.write_str("\n");
             }
+
+            if !provided_methods.is_empty() {
+                write!(w, "    // Provided method{}\n", pluralize(provided_methods.len()));
+            }
             for (pos, m) in provided_methods.iter().enumerate() {
                 render_assoc_item(
                     w,
@@ -672,16 +680,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
                     cx,
                     RenderMode::Normal,
                 );
-                match *m.kind {
-                    clean::MethodItem(ref inner, _)
-                        if !inner.generics.where_predicates.is_empty() =>
-                    {
-                        w.write_str(",\n    { ... }\n");
-                    }
-                    _ => {
-                        w.write_str(" { ... }\n");
-                    }
-                }
+
+                w.write_str(" { ... }\n");
 
                 if pos < provided_methods.len() - 1 {
                     w.write_str("<span class=\"item-spacer\"></span>");
@@ -1157,7 +1157,7 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean:
 fn print_tuple_struct_fields(w: &mut Buffer, cx: &Context<'_>, s: &[clean::Item]) {
     for (i, ty) in s.iter().enumerate() {
         if i > 0 {
-            w.write_str(",&nbsp;");
+            w.write_str(", ");
         }
         match *ty.kind {
             clean::StrippedItem(box clean::StructFieldItem(_)) => w.write_str("_"),
@@ -1297,7 +1297,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
                                 "<div class=\"sub-variant-field\">\
                                  <span id=\"{id}\" class=\"small-section-header\">\
                                      <a href=\"#{id}\" class=\"anchor field\">§</a>\
-                                     <code>{f}:&nbsp;{t}</code>\
+                                     <code>{f}: {t}</code>\
                                  </span>",
                                 id = id,
                                 f = field.name.unwrap(),
index ee988090ca334e9ed2ea02dfebd308b43b113d5a..2a9548712f08637a264d613a7811660d6a5aaf2f 100644 (file)
@@ -184,6 +184,7 @@ h4.code-header {
        font-weight: 600;
        margin: 0;
        padding: 0;
+       white-space: pre-wrap;
 }
 
 #crate-search,
@@ -642,6 +643,7 @@ pre, .rustdoc.source .example-wrap {
 .fn .where,
 .where.fmt-newline {
        display: block;
+       white-space: pre-wrap;
        font-size: 0.875rem;
 }
 
@@ -1174,6 +1176,7 @@ a.test-arrow:hover {
 .item-spacer {
        width: 100%;
        height: 12px;
+       display: block;
 }
 
 .out-of-band > span.since {
index d20d13ab36d2d892ff800792bb778457c52257c2..b5a2cf7f28bf310114eac2ff44f8b6ebd23ac4e4 100644 (file)
@@ -105,10 +105,9 @@ Original by Dempfi (https://github.com/dempfi/ayu)
        --scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0);
 }
 
-h1, h2, h3, h4 {
-       color: white;
-}
-h1 a {
+h1, h2, h3, h4,
+h1 a, .sidebar h2 a, .sidebar h3 a,
+#source-sidebar > .title {
        color: #fff;
 }
 h4 {
@@ -118,24 +117,22 @@ h4 {
 .docblock code {
        color: #ffb454;
 }
-.code-header {
-       color: #e6e1cf;
-}
-.docblock pre > code, pre > code {
-       color: #e6e1cf;
-}
-.item-info code {
-       color: #e6e1cf;
-}
 .docblock a > code {
        color: #39AFD7 !important;
 }
-pre, .rustdoc.source .example-wrap {
+.code-header,
+.docblock pre > code,
+pre, pre > code,
+.item-info code,
+.rustdoc.source .example-wrap {
        color: #e6e1cf;
 }
 
 .sidebar .current,
-.sidebar a:hover {
+.sidebar a:hover,
+#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
+#source-sidebar div.files > a:focus, details.dir-entry summary:focus,
+#source-sidebar div.files > a.selected {
        color: #ffb44c;
 }
 
@@ -149,15 +146,12 @@ pre, .rustdoc.source .example-wrap {
        border-right: 1px solid #ffb44c;
 }
 
-.search-results a:hover {
-       color: #fff !important;
-       background-color: #3c3c3c;
-}
-
+.search-results a:hover,
 .search-results a:focus {
        color: #fff !important;
        background-color: #3c3c3c;
 }
+
 .search-results a {
        color: #0096cf;
 }
@@ -165,11 +159,6 @@ pre, .rustdoc.source .example-wrap {
        color: #c5c5c5;
 }
 
-.sidebar h2 a,
-.sidebar h3 a {
-       color: white;
-}
-
 .result-name .primitive > i, .result-name .keyword > i {
        color: #788797;
 }
@@ -189,12 +178,3 @@ pre, .rustdoc.source .example-wrap {
 #settings-menu > a img {
        filter: invert(100);
 }
-
-#source-sidebar > .title {
-       color: #fff;
-}
-#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
-#source-sidebar div.files > a:focus, details.dir-entry summary:focus,
-#source-sidebar div.files > a.selected {
-       color: #ffb44c;
-}
index 88592fa0c84c1453fbda216b9f3d92eddb0ab307..251e806c2d90d086c5bec0a25ba4769ec3a7ba46 100644 (file)
@@ -112,7 +112,6 @@ function levenshtein(s1, s2) {
 }
 
 function initSearch(rawSearchIndex) {
-    const MAX_LEV_DISTANCE = 3;
     const MAX_RESULTS = 200;
     const NO_TYPE_FILTER = -1;
     /**
@@ -897,13 +896,13 @@ function initSearch(rawSearchIndex) {
          * @param {QueryElement} elem  - The element from the parsed query.
          * @param {integer} defaultLev - This is the value to return in case there are no generics.
          *
-         * @return {integer}           - Returns the best match (if any) or `MAX_LEV_DISTANCE + 1`.
+         * @return {integer}           - Returns the best match (if any) or `maxLevDistance + 1`.
          */
-        function checkGenerics(row, elem, defaultLev) {
+        function checkGenerics(row, elem, defaultLev, maxLevDistance) {
             if (row.generics.length === 0) {
-                return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
+                return elem.generics.length === 0 ? defaultLev : maxLevDistance + 1;
             } else if (row.generics.length > 0 && row.generics[0].name === null) {
-                return checkGenerics(row.generics[0], elem, defaultLev);
+                return checkGenerics(row.generics[0], elem, defaultLev, maxLevDistance);
             }
             // The names match, but we need to be sure that all generics kinda
             // match as well.
@@ -914,8 +913,8 @@ function initSearch(rawSearchIndex) {
                     elem_name = entry.name;
                     if (elem_name === "") {
                         // Pure generic, needs to check into it.
-                        if (checkGenerics(entry, elem, MAX_LEV_DISTANCE + 1) !== 0) {
-                            return MAX_LEV_DISTANCE + 1;
+                        if (checkGenerics(entry, elem, maxLevDistance + 1, maxLevDistance) !== 0) {
+                            return maxLevDistance + 1;
                         }
                         continue;
                     }
@@ -942,7 +941,7 @@ function initSearch(rawSearchIndex) {
                         }
                     }
                     if (match === null) {
-                        return MAX_LEV_DISTANCE + 1;
+                        return maxLevDistance + 1;
                     }
                     elems[match] -= 1;
                     if (elems[match] === 0) {
@@ -951,7 +950,7 @@ function initSearch(rawSearchIndex) {
                 }
                 return 0;
             }
-            return MAX_LEV_DISTANCE + 1;
+            return maxLevDistance + 1;
         }
 
         /**
@@ -963,10 +962,10 @@ function initSearch(rawSearchIndex) {
           *
           * @return {integer} - Returns a Levenshtein distance to the best match.
           */
-        function checkIfInGenerics(row, elem) {
-            let lev = MAX_LEV_DISTANCE + 1;
+        function checkIfInGenerics(row, elem, maxLevDistance) {
+            let lev = maxLevDistance + 1;
             for (const entry of row.generics) {
-                lev = Math.min(checkType(entry, elem, true), lev);
+                lev = Math.min(checkType(entry, elem, true, maxLevDistance), lev);
                 if (lev === 0) {
                     break;
                 }
@@ -983,15 +982,15 @@ function initSearch(rawSearchIndex) {
           * @param {boolean} literalSearch
           *
           * @return {integer} - Returns a Levenshtein distance to the best match. If there is
-          *                     no match, returns `MAX_LEV_DISTANCE + 1`.
+          *                     no match, returns `maxLevDistance + 1`.
           */
-        function checkType(row, elem, literalSearch) {
+        function checkType(row, elem, literalSearch, maxLevDistance) {
             if (row.name === null) {
                 // This is a pure "generic" search, no need to run other checks.
                 if (row.generics.length > 0) {
-                    return checkIfInGenerics(row, elem);
+                    return checkIfInGenerics(row, elem, maxLevDistance);
                 }
-                return MAX_LEV_DISTANCE + 1;
+                return maxLevDistance + 1;
             }
 
             let lev = levenshtein(row.name, elem.name);
@@ -1005,9 +1004,9 @@ function initSearch(rawSearchIndex) {
                             return 0;
                         }
                     }
-                    return MAX_LEV_DISTANCE + 1;
+                    return maxLevDistance + 1;
                 } else if (elem.generics.length > 0) {
-                    return checkGenerics(row, elem, MAX_LEV_DISTANCE + 1);
+                    return checkGenerics(row, elem, maxLevDistance + 1, maxLevDistance);
                 }
                 return 0;
             } else if (row.generics.length > 0) {
@@ -1017,22 +1016,20 @@ function initSearch(rawSearchIndex) {
                     }
                     // The name didn't match so we now check if the type we're looking for is inside
                     // the generics!
-                    lev = checkIfInGenerics(row, elem);
-                    // Now whatever happens, the returned distance is "less good" so we should mark
-                    // it as such, and so we add 0.5 to the distance to make it "less good".
-                    return lev + 0.5;
-                } else if (lev > MAX_LEV_DISTANCE) {
+                    lev = Math.min(lev, checkIfInGenerics(row, elem, maxLevDistance));
+                    return lev;
+                } else if (lev > maxLevDistance) {
                     // So our item's name doesn't match at all and has generics.
                     //
                     // Maybe it's present in a sub generic? For example "f<A<B<C>>>()", if we're
                     // looking for "B<C>", we'll need to go down.
-                    return checkIfInGenerics(row, elem);
+                    return checkIfInGenerics(row, elem, maxLevDistance);
                 } else {
                     // At this point, the name kinda match and we have generics to check, so
                     // let's go!
-                    const tmp_lev = checkGenerics(row, elem, lev);
-                    if (tmp_lev > MAX_LEV_DISTANCE) {
-                        return MAX_LEV_DISTANCE + 1;
+                    const tmp_lev = checkGenerics(row, elem, lev, maxLevDistance);
+                    if (tmp_lev > maxLevDistance) {
+                        return maxLevDistance + 1;
                     }
                     // We compute the median value of both checks and return it.
                     return (tmp_lev + lev) / 2;
@@ -1040,7 +1037,7 @@ function initSearch(rawSearchIndex) {
             } else if (elem.generics.length > 0) {
                 // In this case, we were expecting generics but there isn't so we simply reject this
                 // one.
-                return MAX_LEV_DISTANCE + 1;
+                return maxLevDistance + 1;
             }
             // No generics on our query or on the target type so we can return without doing
             // anything else.
@@ -1055,23 +1052,26 @@ function initSearch(rawSearchIndex) {
          * @param {integer} typeFilter
          *
          * @return {integer} - Returns a Levenshtein distance to the best match. If there is no
-         *                      match, returns `MAX_LEV_DISTANCE + 1`.
+         *                      match, returns `maxLevDistance + 1`.
          */
-        function findArg(row, elem, typeFilter) {
-            let lev = MAX_LEV_DISTANCE + 1;
+        function findArg(row, elem, typeFilter, maxLevDistance) {
+            let lev = maxLevDistance + 1;
 
             if (row && row.type && row.type.inputs && row.type.inputs.length > 0) {
                 for (const input of row.type.inputs) {
                     if (!typePassesFilter(typeFilter, input.ty)) {
                         continue;
                     }
-                    lev = Math.min(lev, checkType(input, elem, parsedQuery.literalSearch));
+                    lev = Math.min(
+                        lev,
+                        checkType(input, elem, parsedQuery.literalSearch, maxLevDistance)
+                    );
                     if (lev === 0) {
                         return 0;
                     }
                 }
             }
-            return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
+            return parsedQuery.literalSearch ? maxLevDistance + 1 : lev;
         }
 
         /**
@@ -1082,10 +1082,10 @@ function initSearch(rawSearchIndex) {
          * @param {integer} typeFilter
          *
          * @return {integer} - Returns a Levenshtein distance to the best match. If there is no
-         *                      match, returns `MAX_LEV_DISTANCE + 1`.
+         *                      match, returns `maxLevDistance + 1`.
          */
-        function checkReturned(row, elem, typeFilter) {
-            let lev = MAX_LEV_DISTANCE + 1;
+        function checkReturned(row, elem, typeFilter, maxLevDistance) {
+            let lev = maxLevDistance + 1;
 
             if (row && row.type && row.type.output.length > 0) {
                 const ret = row.type.output;
@@ -1093,20 +1093,23 @@ function initSearch(rawSearchIndex) {
                     if (!typePassesFilter(typeFilter, ret_ty.ty)) {
                         continue;
                     }
-                    lev = Math.min(lev, checkType(ret_ty, elem, parsedQuery.literalSearch));
+                    lev = Math.min(
+                        lev,
+                        checkType(ret_ty, elem, parsedQuery.literalSearch, maxLevDistance)
+                    );
                     if (lev === 0) {
                         return 0;
                     }
                 }
             }
-            return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
+            return parsedQuery.literalSearch ? maxLevDistance + 1 : lev;
         }
 
-        function checkPath(contains, ty) {
+        function checkPath(contains, ty, maxLevDistance) {
             if (contains.length === 0) {
                 return 0;
             }
-            let ret_lev = MAX_LEV_DISTANCE + 1;
+            let ret_lev = maxLevDistance + 1;
             const path = ty.path.split("::");
 
             if (ty.parent && ty.parent.name) {
@@ -1116,7 +1119,7 @@ function initSearch(rawSearchIndex) {
             const length = path.length;
             const clength = contains.length;
             if (clength > length) {
-                return MAX_LEV_DISTANCE + 1;
+                return maxLevDistance + 1;
             }
             for (let i = 0; i < length; ++i) {
                 if (i + clength > length) {
@@ -1126,7 +1129,7 @@ function initSearch(rawSearchIndex) {
                 let aborted = false;
                 for (let x = 0; x < clength; ++x) {
                     const lev = levenshtein(path[i + x], contains[x]);
-                    if (lev > MAX_LEV_DISTANCE) {
+                    if (lev > maxLevDistance) {
                         aborted = true;
                         break;
                     }
@@ -1231,7 +1234,7 @@ function initSearch(rawSearchIndex) {
          * following condition:
          *
          * * If it is a "literal search" (`parsedQuery.literalSearch`), then `lev` must be 0.
-         * * If it is not a "literal search", `lev` must be <= `MAX_LEV_DISTANCE`.
+         * * If it is not a "literal search", `lev` must be <= `maxLevDistance`.
          *
          * The `results` map contains information which will be used to sort the search results:
          *
@@ -1249,8 +1252,8 @@ function initSearch(rawSearchIndex) {
          * @param {integer} lev
          * @param {integer} path_lev
          */
-        function addIntoResults(results, fullId, id, index, lev, path_lev) {
-            const inBounds = lev <= MAX_LEV_DISTANCE || index !== -1;
+        function addIntoResults(results, fullId, id, index, lev, path_lev, maxLevDistance) {
+            const inBounds = lev <= maxLevDistance || index !== -1;
             if (lev === 0 || (!parsedQuery.literalSearch && inBounds)) {
                 if (results[fullId] !== undefined) {
                     const result = results[fullId];
@@ -1289,7 +1292,8 @@ function initSearch(rawSearchIndex) {
             elem,
             results_others,
             results_in_args,
-            results_returned
+            results_returned,
+            maxLevDistance
         ) {
             if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
                 return;
@@ -1298,13 +1302,13 @@ function initSearch(rawSearchIndex) {
             const fullId = row.id;
             const searchWord = searchWords[pos];
 
-            const in_args = findArg(row, elem, parsedQuery.typeFilter);
-            const returned = checkReturned(row, elem, parsedQuery.typeFilter);
+            const in_args = findArg(row, elem, parsedQuery.typeFilter, maxLevDistance);
+            const returned = checkReturned(row, elem, parsedQuery.typeFilter, maxLevDistance);
 
             // 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);
+            addIntoResults(results_in_args, fullId, pos, -1, in_args, 0, maxLevDistance);
+            addIntoResults(results_returned, fullId, pos, -1, returned, 0, maxLevDistance);
 
             if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
                 return;
@@ -1328,16 +1332,16 @@ function initSearch(rawSearchIndex) {
             // 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);
+                    lev = checkGenerics(row.type, elem, maxLevDistance + 1, maxLevDistance);
                     // path_lev is 0 because we know it's empty
-                    addIntoResults(results_others, fullId, pos, index, lev, 0);
+                    addIntoResults(results_others, fullId, pos, index, lev, 0, maxLevDistance);
                 }
                 return;
             }
 
             if (elem.fullPath.length > 1) {
-                path_lev = checkPath(elem.pathWithoutLast, row);
-                if (path_lev > MAX_LEV_DISTANCE) {
+                path_lev = checkPath(elem.pathWithoutLast, row, maxLevDistance);
+                if (path_lev > maxLevDistance) {
                     return;
                 }
             }
@@ -1351,11 +1355,11 @@ function initSearch(rawSearchIndex) {
 
             lev = levenshtein(searchWord, elem.pathLast);
 
-            if (index === -1 && lev + path_lev > MAX_LEV_DISTANCE) {
+            if (index === -1 && lev + path_lev > maxLevDistance) {
                 return;
             }
 
-            addIntoResults(results_others, fullId, pos, index, lev, path_lev);
+            addIntoResults(results_others, fullId, pos, index, lev, path_lev, maxLevDistance);
         }
 
         /**
@@ -1367,7 +1371,7 @@ function initSearch(rawSearchIndex) {
          * @param {integer} pos      - Position in the `searchIndex`.
          * @param {Object} results
          */
-        function handleArgs(row, pos, results) {
+        function handleArgs(row, pos, results, maxLevDistance) {
             if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
                 return;
             }
@@ -1379,7 +1383,7 @@ function initSearch(rawSearchIndex) {
             function checkArgs(elems, callback) {
                 for (const elem of elems) {
                     // There is more than one parameter to the query so all checks should be "exact"
-                    const lev = callback(row, elem, NO_TYPE_FILTER);
+                    const lev = callback(row, elem, NO_TYPE_FILTER, maxLevDistance);
                     if (lev <= 1) {
                         nbLev += 1;
                         totalLev += lev;
@@ -1400,12 +1404,21 @@ function initSearch(rawSearchIndex) {
                 return;
             }
             const lev = Math.round(totalLev / nbLev);
-            addIntoResults(results, row.id, pos, 0, lev, 0);
+            addIntoResults(results, row.id, pos, 0, lev, 0, maxLevDistance);
         }
 
         function innerRunQuery() {
             let elem, i, nSearchWords, in_returned, row;
 
+            let queryLen = 0;
+            for (const elem of parsedQuery.elems) {
+                queryLen += elem.name.length;
+            }
+            for (const elem of parsedQuery.returned) {
+                queryLen += elem.name.length;
+            }
+            const maxLevDistance = Math.floor(queryLen / 3);
+
             if (parsedQuery.foundElems === 1) {
                 if (parsedQuery.elems.length === 1) {
                     elem = parsedQuery.elems[0];
@@ -1418,7 +1431,8 @@ function initSearch(rawSearchIndex) {
                             elem,
                             results_others,
                             results_in_args,
-                            results_returned
+                            results_returned,
+                            maxLevDistance
                         );
                     }
                 } else if (parsedQuery.returned.length === 1) {
@@ -1426,13 +1440,18 @@ function initSearch(rawSearchIndex) {
                     elem = parsedQuery.returned[0];
                     for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
                         row = searchIndex[i];
-                        in_returned = checkReturned(row, elem, parsedQuery.typeFilter);
-                        addIntoResults(results_others, row.id, i, -1, in_returned);
+                        in_returned = checkReturned(
+                            row,
+                            elem,
+                            parsedQuery.typeFilter,
+                            maxLevDistance
+                        );
+                        addIntoResults(results_others, row.id, i, -1, in_returned, maxLevDistance);
                     }
                 }
             } else if (parsedQuery.foundElems > 0) {
                 for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
-                    handleArgs(searchIndex[i], i, results_others);
+                    handleArgs(searchIndex[i], i, results_others, maxLevDistance);
                 }
             }
         }
@@ -1470,7 +1489,7 @@ function initSearch(rawSearchIndex) {
      *
      * @return {boolean}       - Whether the result is valid or not
      */
-    function validateResult(name, path, keys, parent) {
+    function validateResult(name, path, keys, parent, maxLevDistance) {
         if (!keys || !keys.length) {
             return true;
         }
@@ -1485,7 +1504,7 @@ function initSearch(rawSearchIndex) {
                 (parent !== undefined && parent.name !== undefined &&
                     parent.name.toLowerCase().indexOf(key) > -1) ||
                 // lastly check to see if the name was a levenshtein match
-                levenshtein(name, key) <= MAX_LEV_DISTANCE)) {
+                levenshtein(name, key) <= maxLevDistance)) {
                 return false;
             }
         }
index 8540ee6631934c7d163644fd17e52553b9f5b1a2..7690d8f251f7485a04affbcb445b9b6ca7486687 100644 (file)
     {%- for theme in themes -%}
         <link rel="stylesheet" disabled href="{{page.root_path|safe}}{{theme}}{{page.resource_suffix}}.css"> {#- -#}
     {%- endfor -%}
+    {%- if !layout.default_settings.is_empty() -%}
     <script id="default-settings" {# -#}
       {% for (k, v) in layout.default_settings %}
         data-{{k}}="{{v}}"
       {%- endfor -%}
     ></script> {#- -#}
+    {%- endif -%}
     <script src="{{static_root_path|safe}}{{files.storage_js}}"></script> {#- -#}
     {%- if page.css_class.contains("crate") -%}
     <script defer src="{{page.root_path|safe}}crates{{page.resource_suffix}}.js"></script> {#- -#}
index 5f4ad6d2aea345073d79b30dcf5baf38dbfeeda8..4321d4aa343dcd8f7065ee0134975e5740b7add8 100644 (file)
@@ -72,7 +72,14 @@ pub(crate) fn render<P: AsRef<Path>>(
     let mut ids = IdMap::new();
     let error_codes = ErrorCodes::from(options.unstable_features.is_nightly_build());
     let text = if !options.markdown_no_toc {
-        MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string()
+        MarkdownWithToc {
+            content: text,
+            ids: &mut ids,
+            error_codes,
+            edition,
+            playground: &playground,
+        }
+        .into_string()
     } else {
         Markdown {
             content: text,
index 8992d165d5d504a783e6a5bf3f25f1fd7150598a..3fc72ecbbc484ffd2b9e292b00585fcbedeeb392 100644 (file)
@@ -51,7 +51,7 @@ fn from_args() -> Result<Self, Box<dyn Error>> {
             ["generate", ref base] => (Mode::Generate, PathBuf::from(base)),
             ["check", ref base] => (Mode::Check, PathBuf::from(base)),
             _ => {
-                eprintln!("usage: expand-yaml-anchors <source-dir> <dest-dir>");
+                eprintln!("usage: expand-yaml-anchors <generate|check> <base-dir>");
                 std::process::exit(1);
             }
         };
index ec555ba2895c8468b82bcaae0008fcfb34b13ad0..106e93751d21904c363c07bf26413a75505c78a7 100644 (file)
@@ -81,21 +81,18 @@ fn from_ref_ty<'tcx>(
                         protector: None,
                     }
                 } else if pointee.is_unpin(*cx.tcx, cx.param_env()) {
-                    // A regular full mutable reference.
+                    // A regular full mutable reference. On `FnEntry` this is `noalias` and `dereferenceable`.
                     NewPermission::Uniform {
                         perm: Permission::Unique,
                         access: Some(AccessKind::Write),
                         protector,
                     }
                 } else {
+                    // `!Unpin` dereferences do not get `noalias` nor `dereferenceable`.
                     NewPermission::Uniform {
                         perm: Permission::SharedReadWrite,
-                        // FIXME: We emit `dereferenceable` for `!Unpin` mutable references, so we
-                        // should do fake accesses here. But then we run into
-                        // <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>, so for now
-                        // we don't do that.
                         access: None,
-                        protector,
+                        protector: None,
                     }
                 }
             }
@@ -109,6 +106,7 @@ fn from_ref_ty<'tcx>(
                 }
             }
             ty::Ref(_, _pointee, Mutability::Not) => {
+                // Shared references. If frozen, these get `noalias` and `dereferenceable`; otherwise neither.
                 NewPermission::FreezeSensitive {
                     freeze_perm: Permission::SharedReadOnly,
                     freeze_access: Some(AccessKind::Read),
@@ -137,6 +135,32 @@ fn from_ref_ty<'tcx>(
         }
     }
 
+    fn from_box_ty<'tcx>(
+        ty: Ty<'tcx>,
+        kind: RetagKind,
+        cx: &crate::MiriInterpCx<'_, 'tcx>,
+    ) -> Self {
+        // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling).
+        let pointee = ty.builtin_deref(true).unwrap().ty;
+        if pointee.is_unpin(*cx.tcx, cx.param_env()) {
+            // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only
+            // a weak protector).
+            NewPermission::Uniform {
+                perm: Permission::Unique,
+                access: Some(AccessKind::Write),
+                protector: (kind == RetagKind::FnEntry)
+                    .then_some(ProtectorKind::WeakProtector),
+            }
+        } else {
+            // `!Unpin` boxes do not get `noalias` nor `dereferenceable`.
+            NewPermission::Uniform {
+                perm: Permission::SharedReadWrite,
+                access: None,
+                protector: None,
+            }
+        }
+    }
+
     fn protector(&self) -> Option<ProtectorKind> {
         match self {
             NewPermission::Uniform { protector, .. } => *protector,
@@ -916,12 +940,7 @@ fn ecx(&mut self) -> &mut MiriInterpCx<'mir, 'tcx> {
 
             fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
                 // Boxes get a weak protectors, since they may be deallocated.
-                let new_perm = NewPermission::Uniform {
-                    perm: Permission::Unique,
-                    access: Some(AccessKind::Write),
-                    protector: (self.kind == RetagKind::FnEntry)
-                        .then_some(ProtectorKind::WeakProtector),
-                };
+                let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
                 self.retag_ptr_inplace(place, new_perm, self.retag_cause)
             }
 
index 618cf9df7f3f0f54e9e28dc71046965d3e3fc5cb..dcb1879042041daa9e9a0d520c4ef7d7265db366 100644 (file)
@@ -162,11 +162,14 @@ pub fn ptr_from_addr_cast(
         Ok(Pointer::new(Some(Provenance::Wildcard), Size::from_bytes(addr)))
     }
 
-    fn alloc_base_addr(ecx: &MiriInterpCx<'mir, 'tcx>, alloc_id: AllocId) -> u64 {
+    fn alloc_base_addr(
+        ecx: &MiriInterpCx<'mir, 'tcx>,
+        alloc_id: AllocId,
+    ) -> InterpResult<'tcx, u64> {
         let mut global_state = ecx.machine.intptrcast.borrow_mut();
         let global_state = &mut *global_state;
 
-        match global_state.base_addr.entry(alloc_id) {
+        Ok(match global_state.base_addr.entry(alloc_id) {
             Entry::Occupied(entry) => *entry.get(),
             Entry::Vacant(entry) => {
                 // There is nothing wrong with a raw pointer being cast to an integer only after
@@ -181,7 +184,10 @@ fn alloc_base_addr(ecx: &MiriInterpCx<'mir, 'tcx>, alloc_id: AllocId) -> u64 {
                     rng.gen_range(0..16)
                 };
                 // From next_base_addr + slack, round up to adjust for alignment.
-                let base_addr = global_state.next_base_addr.checked_add(slack).unwrap();
+                let base_addr = global_state
+                    .next_base_addr
+                    .checked_add(slack)
+                    .ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
                 let base_addr = Self::align_addr(base_addr, align.bytes());
                 entry.insert(base_addr);
                 trace!(
@@ -197,24 +203,33 @@ fn alloc_base_addr(ecx: &MiriInterpCx<'mir, 'tcx>, alloc_id: AllocId) -> u64 {
                 // of at least 1 to avoid two allocations having the same base address.
                 // (The logic in `alloc_id_from_addr` assumes unique addresses, and different
                 // function/vtable pointers need to be distinguishable!)
-                global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap();
+                global_state.next_base_addr = base_addr
+                    .checked_add(max(size.bytes(), 1))
+                    .ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
+                // Even if `Size` didn't overflow, we might still have filled up the address space.
+                if global_state.next_base_addr > ecx.machine_usize_max() {
+                    throw_exhaust!(AddressSpaceFull);
+                }
                 // Given that `next_base_addr` increases in each allocation, pushing the
                 // corresponding tuple keeps `int_to_ptr_map` sorted
                 global_state.int_to_ptr_map.push((base_addr, alloc_id));
 
                 base_addr
             }
-        }
+        })
     }
 
     /// Convert a relative (tcx) pointer to an absolute address.
-    pub fn rel_ptr_to_addr(ecx: &MiriInterpCx<'mir, 'tcx>, ptr: Pointer<AllocId>) -> u64 {
+    pub fn rel_ptr_to_addr(
+        ecx: &MiriInterpCx<'mir, 'tcx>,
+        ptr: Pointer<AllocId>,
+    ) -> InterpResult<'tcx, u64> {
         let (alloc_id, offset) = ptr.into_parts(); // offset is relative (AllocId provenance)
-        let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id);
+        let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id)?;
 
         // Add offset with the right kind of pointer-overflowing arithmetic.
         let dl = ecx.data_layout();
-        dl.overflowing_offset(base_addr, offset.bytes()).0
+        Ok(dl.overflowing_offset(base_addr, offset.bytes()).0)
     }
 
     /// When a pointer is used for a memory access, this computes where in which allocation the
@@ -232,7 +247,9 @@ pub fn abs_ptr_to_rel(
             GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes())?
         };
 
-        let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id);
+        // This cannot fail: since we already have a pointer with that provenance, rel_ptr_to_addr
+        // must have been called in the past.
+        let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id).unwrap();
 
         // Wrapping "addr - base_addr"
         let dl = ecx.data_layout();
index 01a3d7550e2e0c480b5bb545ef77782837471924..8e44d4d7adec8465607827b6ba9f06529a623ce3 100644 (file)
@@ -971,7 +971,7 @@ fn adjust_allocation<'b>(
     fn adjust_alloc_base_pointer(
         ecx: &MiriInterpCx<'mir, 'tcx>,
         ptr: Pointer<AllocId>,
-    ) -> Pointer<Provenance> {
+    ) -> InterpResult<'tcx, Pointer<Provenance>> {
         if cfg!(debug_assertions) {
             // The machine promises to never call us on thread-local or extern statics.
             let alloc_id = ptr.provenance;
@@ -985,17 +985,17 @@ fn adjust_alloc_base_pointer(
                 _ => {}
             }
         }
-        let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr);
+        let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr)?;
         let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
             borrow_tracker.borrow_mut().base_ptr_tag(ptr.provenance, &ecx.machine)
         } else {
             // Value does not matter, SB is disabled
             BorTag::default()
         };
-        Pointer::new(
+        Ok(Pointer::new(
             Provenance::Concrete { alloc_id: ptr.provenance, tag },
             Size::from_bytes(absolute_addr),
-        )
+        ))
     }
 
     #[inline(always)]
index 15987eee537fd72372cab58e2c654ab206631c9e..ed1c6ebfece76ceed96988a2385a21c6d0145065 100644 (file)
@@ -190,9 +190,9 @@ fn handle_miri_resolve_frame(
             0 => {
                 // These are "mutable" allocations as we consider them to be owned by the callee.
                 let name_alloc =
-                    this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut);
+                    this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
                 let filename_alloc =
-                    this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut);
+                    this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
 
                 this.write_immediate(
                     name_alloc.to_ref(this),
index db3e42facadd03958c1d8725b7c44be4645692db..0ea1137200b9d98177de5a0770fa040a7fd19471 100644 (file)
@@ -172,7 +172,7 @@ fn start_panic(&mut self, msg: &str, unwind: StackPopUnwind) -> InterpResult<'tc
         let this = self.eval_context_mut();
 
         // First arg: message.
-        let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not);
+        let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not)?;
 
         // Call the lang item.
         let panic = this.tcx.lang_items().panic_fn().unwrap();
diff --git a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.rs b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.rs
deleted file mode 100644 (file)
index fd67dcc..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-//@error-pattern: /deallocating while item \[SharedReadWrite for .*\] is strongly protected/
-use std::marker::PhantomPinned;
-
-pub struct NotUnpin(i32, PhantomPinned);
-
-fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
-    // `f` may mutate, but it may not deallocate!
-    f(x)
-}
-
-fn main() {
-    inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
-        let raw = x as *mut _;
-        drop(unsafe { Box::from_raw(raw) });
-    });
-}
diff --git a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.stderr b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.stderr
deleted file mode 100644 (file)
index 47cfa0d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-error: Undefined Behavior: deallocating while item [SharedReadWrite for <TAG>] is strongly protected by call ID
-  --> RUSTLIB/alloc/src/alloc.rs:LL:CC
-   |
-LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [SharedReadWrite for <TAG>] is strongly protected by call ID
-   |
-   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
-   = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
-   = note: BACKTRACE:
-   = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `alloc::alloc::box_free::<NotUnpin, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `std::ptr::drop_in_place::<std::boxed::Box<NotUnpin>> - shim(Some(std::boxed::Box<NotUnpin>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
-   = note: inside `std::mem::drop::<std::boxed::Box<NotUnpin>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
-note: inside closure
-  --> $DIR/deallocate_against_protector2.rs:LL:CC
-   |
-LL |         drop(unsafe { Box::from_raw(raw) });
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: inside `<[closure@$DIR/deallocate_against_protector2.rs:LL:CC] as std::ops::FnOnce<(&mut NotUnpin,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC
-note: inside `inner`
-  --> $DIR/deallocate_against_protector2.rs:LL:CC
-   |
-LL |     f(x)
-   |     ^^^^
-note: inside `main`
-  --> $DIR/deallocate_against_protector2.rs:LL:CC
-   |
-LL | /     inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
-LL | |         let raw = x as *mut _;
-LL | |         drop(unsafe { Box::from_raw(raw) });
-LL | |     });
-   | |______^
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to previous error
-
index 96fc0be344dbfea2f8065c503b4df6b3057d0a7c..6994def16a1da3f537c9fb78bdc4a8622c2d13d5 100644 (file)
@@ -26,6 +26,19 @@ fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
     }
 }
 
+fn mk_waker() -> Waker {
+    use std::sync::Arc;
+
+    struct MyWaker;
+    impl Wake for MyWaker {
+        fn wake(self: Arc<Self>) {
+            unimplemented!()
+        }
+    }
+
+    Waker::from(Arc::new(MyWaker))
+}
+
 async fn do_stuff() {
     (&mut Delay::new(1)).await;
 }
@@ -73,16 +86,7 @@ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
 }
 
 fn run_fut<T>(fut: impl Future<Output = T>) -> T {
-    use std::sync::Arc;
-
-    struct MyWaker;
-    impl Wake for MyWaker {
-        fn wake(self: Arc<Self>) {
-            unimplemented!()
-        }
-    }
-
-    let waker = Waker::from(Arc::new(MyWaker));
+    let waker = mk_waker();
     let mut context = Context::from_waker(&waker);
 
     let mut pinned = pin!(fut);
@@ -94,7 +98,37 @@ fn wake(self: Arc<Self>) {
     }
 }
 
+fn self_referential_box() {
+    let waker = mk_waker();
+    let cx = &mut Context::from_waker(&waker);
+
+    async fn my_fut() -> i32 {
+        let val = 10;
+        let val_ref = &val;
+
+        let _ = Delay::new(1).await;
+
+        *val_ref
+    }
+
+    fn box_poll<F: Future>(
+        mut f: Pin<Box<F>>,
+        cx: &mut Context<'_>,
+    ) -> (Pin<Box<F>>, Poll<F::Output>) {
+        let p = f.as_mut().poll(cx);
+        (f, p)
+    }
+
+    let my_fut = Box::pin(my_fut());
+    let (my_fut, p1) = box_poll(my_fut, cx);
+    assert!(p1.is_pending());
+    let (my_fut, p2) = box_poll(my_fut, cx);
+    assert!(p2.is_ready());
+    drop(my_fut);
+}
+
 fn main() {
     run_fut(do_stuff());
     run_fut(DoStuff::new());
+    self_referential_box();
 }
index ef6eb346c17b12804cb9c92dd5caaa424d35dbec..8e78efa73c751578c9c3b7849553bb62fcd32e31 100644 (file)
@@ -19,6 +19,7 @@ fn main() {
     array_casts();
     mut_below_shr();
     wide_raw_ptr_in_tuple();
+    not_unpin_not_protected();
 }
 
 // Make sure that reading from an `&mut` does, like reborrowing to `&`,
@@ -219,3 +220,22 @@ fn wide_raw_ptr_in_tuple() {
     // Make sure the fn ptr part of the vtable is still fine.
     r.type_id();
 }
+
+fn not_unpin_not_protected() {
+    // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also
+    // don't add protectors. (We could, but until we have a better idea for where we want to go with
+    // the self-referntial-generator situation, it does not seem worth the potential trouble.)
+    use std::marker::PhantomPinned;
+
+    pub struct NotUnpin(i32, PhantomPinned);
+
+    fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
+        // `f` may mutate, but it may not deallocate!
+        f(x)
+    }
+
+    inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
+        let raw = x as *mut _;
+        drop(unsafe { Box::from_raw(raw) });
+    });
+}
index 6bb4d32f87d0a25bd2b5a065741ce3e3fc5e6cb8..dd2fd1911f227c162b9b249b5a0e2c268dc538b8 100644 (file)
@@ -31,7 +31,7 @@
 
 // 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"];
+    &["E0461", "E0465", "E0476", "E0514", "E0554", "E0640", "E0717", "E0729"];
 
 macro_rules! verbose_print {
     ($verbose:expr, $($fmt:tt)*) => {
index 806e84025c4a28cb37b5f841f70e6580e27d1bcc..83551a1d820abe0c5c30ce395dd968100f813638 100644 (file)
@@ -10,7 +10,7 @@
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
 const ROOT_ENTRY_LIMIT: usize = 939;
-const ISSUES_ENTRY_LIMIT: usize = 1998;
+const ISSUES_ENTRY_LIMIT: usize = 2001;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     for dir in Walk::new(&path.join("ui")) {
index ff76405a4ea323338c45c98751756216f76f4f30..0c62e0d35e36d91624e2ac519e56f1cc72d9c91e 100644 (file)
@@ -29,6 +29,12 @@ pub fn borrow(x: &i32) -> &i32 {
   x
 }
 
+// CHECK: align 4 {{i32\*|ptr}} @borrow_mut({{i32\*|ptr}} align 4 %x)
+#[no_mangle]
+pub fn borrow_mut(x: &mut i32) -> &mut i32 {
+  x
+}
+
 // CHECK-LABEL: @borrow_call
 #[no_mangle]
 pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 {
index 1f979d7b90a70b08b7a5edd95028777218481772..96dfde18683e34b2c3ab452a79920edd040a72a1 100644 (file)
@@ -85,6 +85,12 @@ pub fn option_nonzero_int(x: Option<NonZeroU64>) -> Option<NonZeroU64> {
 pub fn readonly_borrow(_: &i32) {
 }
 
+// CHECK: noundef align 4 dereferenceable(4) {{i32\*|ptr}} @readonly_borrow_ret()
+#[no_mangle]
+pub fn readonly_borrow_ret() -> &'static i32 {
+  loop {}
+}
+
 // CHECK: @static_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
 // static borrow may be captured
 #[no_mangle]
@@ -115,9 +121,17 @@ pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
 pub fn mutable_borrow(_: &mut i32) {
 }
 
+// CHECK: noundef align 4 dereferenceable(4) {{i32\*|ptr}} @mutable_borrow_ret()
+#[no_mangle]
+pub fn mutable_borrow_ret() -> &'static mut i32 {
+  loop {}
+}
+
 #[no_mangle]
-// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef align 4 dereferenceable(4) %_1)
+// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef nonnull align 4 %_1)
 // This one is *not* `noalias` because it might be self-referential.
+// It is also not `dereferenceable` due to
+// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>.
 pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {
 }
 
@@ -167,6 +181,12 @@ pub fn _box(x: Box<i32>) -> Box<i32> {
   x
 }
 
+// CHECK: noundef nonnull align 4 {{i32\*|ptr}} @notunpin_box({{i32\*|ptr}} noundef nonnull align 4 %x)
+#[no_mangle]
+pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
+  x
+}
+
 // CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) dereferenceable(32){{( %0)?}})
 #[no_mangle]
 pub fn struct_return() -> S {
@@ -233,12 +253,12 @@ 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<dyn Drop>) {
+pub fn trait_box(_: Box<dyn Drop + Unpin>) {
 }
 
 // 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<dyn Drop>>) -> Option<Box<dyn Drop>> {
+pub fn trait_option(x: Option<Box<dyn Drop + Unpin>>) -> Option<Box<dyn Drop + Unpin>> {
   x
 }
 
index 2a7f90fe9476a4513c6bbe2478399b7022f0aa75..accb504c088ef83a59712586f62a954d1e2084c4 100644 (file)
@@ -24,9 +24,7 @@ fn a::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:11:14: 11: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
+        _0 = Poll::<()>::Ready(move _3); // 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
     }
index 1449247aedad3c57808717a5d60703b4652146cb..ad4e5c6fcfd72e99795e0ac6bff1a69e51b7a54a 100644 (file)
@@ -167,8 +167,7 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
         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
+        _0 = Poll::<()>::Pending;        // 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
     }
@@ -276,8 +275,7 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
         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
+        _0 = Poll::<()>::Pending;        // 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
     }
@@ -317,9 +315,7 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17: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
+        _0 = Poll::<()>::Ready(move _37); // 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
     }
index 6f01553eef6da4d7ef9550dbab6f5440d11b10e9..20b0fb9643ee622bf73b10d3981f15769d9a7e73 100644 (file)
   
       bb3: {
           StorageDead(_9);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:10:15: 10:16
-          Deinit(_0);                      // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:10: +0:15
-          (_0.0: T) = move _2;             // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:10: +0:15
-          (_0.1: u64) = move _5;           // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:10: +0:15
-          (_0.2: [f32; 3]) = move _8;      // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:10: +0:15
+          _0 = MyThing::<T> { v: move _2, i: move _5, a: move _8 }; // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:10: +0:15
           StorageDead(_8);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15
           StorageDead(_5);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15
           StorageDead(_2);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15
index 6140fc52f650e88de055efd6559db8bedf63c29f..9b69f79c28ee72978d69625ae1371f73926e350e 100644 (file)
@@ -26,17 +26,17 @@ alloc1 (static: FOO, size: 8, align: 4) {
 
 alloc18 (size: 48, align: 4) {
     0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc5──╼ 00 00 00 00 │ ....░░░░╾──╼....
-    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc9──╼ 02 00 00 00 │ ....░░░░╾──╼....
-    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc14─╼ 03 00 00 00 │ ....*...╾──╼....
+    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 02 00 00 00 │ ....░░░░╾──╼....
+    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc13─╼ 03 00 00 00 │ ....*...╾──╼....
 }
 
 alloc5 (size: 0, align: 4) {}
 
-alloc9 (size: 16, align: 4) {
-    ╾─alloc8──╼ 03 00 00 00 ╾─alloc10─╼ 03 00 00 00 │ ╾──╼....╾──╼....
+alloc8 (size: 16, align: 4) {
+    ╾─alloc9──╼ 03 00 00 00 ╾─alloc10─╼ 03 00 00 00 │ ╾──╼....╾──╼....
 }
 
-alloc8 (size: 3, align: 1) {
+alloc9 (size: 3, align: 1) {
     66 6f 6f                                        │ foo
 }
 
@@ -44,12 +44,12 @@ alloc10 (size: 3, align: 1) {
     62 61 72                                        │ bar
 }
 
-alloc14 (size: 24, align: 4) {
-    0x00 │ ╾─alloc13─╼ 03 00 00 00 ╾─alloc15─╼ 03 00 00 00 │ ╾──╼....╾──╼....
+alloc13 (size: 24, align: 4) {
+    0x00 │ ╾─alloc14─╼ 03 00 00 00 ╾─alloc15─╼ 03 00 00 00 │ ╾──╼....╾──╼....
     0x10 │ ╾─alloc16─╼ 04 00 00 00                         │ ╾──╼....
 }
 
-alloc13 (size: 3, align: 1) {
+alloc14 (size: 3, align: 1) {
     6d 65 68                                        │ meh
 }
 
index b2ed23c6873cdf71e9ade7c9afa919652abf87e2..d0f196e724581e0a1a0a2512864220d50d7bcde8 100644 (file)
@@ -27,19 +27,19 @@ alloc1 (static: FOO, size: 16, align: 8) {
 alloc18 (size: 72, align: 8) {
     0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc5────────╼ │ ....░░░░╾──────╼
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
-    0x20 │ ╾───────alloc9────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc14───────╼ │ ....*...╾──────╼
+    0x20 │ ╾───────alloc8────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc13───────╼ │ ....*...╾──────╼
     0x40 │ 03 00 00 00 00 00 00 00                         │ ........
 }
 
 alloc5 (size: 0, align: 8) {}
 
-alloc9 (size: 32, align: 8) {
-    0x00 │ ╾───────alloc8────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+alloc8 (size: 32, align: 8) {
+    0x00 │ ╾───────alloc9────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
     0x10 │ ╾───────alloc10───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
-alloc8 (size: 3, align: 1) {
+alloc9 (size: 3, align: 1) {
     66 6f 6f                                        │ foo
 }
 
@@ -47,13 +47,13 @@ alloc10 (size: 3, align: 1) {
     62 61 72                                        │ bar
 }
 
-alloc14 (size: 48, align: 8) {
-    0x00 │ ╾───────alloc13───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+alloc13 (size: 48, align: 8) {
+    0x00 │ ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
     0x10 │ ╾───────alloc15───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
     0x20 │ ╾───────alloc16───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
-alloc13 (size: 3, align: 1) {
+alloc14 (size: 3, align: 1) {
     6d 65 68                                        │ meh
 }
 
index 4405b55875ed92ed4f401c9ead6a1cfa5e4230c7..f1f53a481655ca6e3ec7685527f2c440acec5ff8 100644 (file)
           StorageLive(_14);                // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
           StorageLive(_15);                // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
           StorageLive(_16);                // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
-          Deinit(_14);                     // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
-          Deinit(_15);                     // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
-          Deinit(_16);                     // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
           _14 = const true;                // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
           _15 = const false;               // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
           _16 = const 123_u32;             // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
           StorageLive(_10);                // scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10
-          Deinit(_10);                     // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
-          ((_10 as Some).0: u16) = const 99_u16; // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
-          discriminant(_10) = 1;           // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
-          StorageLive(_17);                // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
-          StorageLive(_18);                // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
-          Deinit(_17);                     // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
-          Deinit(_18);                     // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
+          _10 = Option::<u16>::Some(const 99_u16); // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
           _17 = const 32_u32;              // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
           _18 = const 32_u32;              // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
           StorageLive(_11);                // scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10
-          StorageLive(_12);                // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16
-          _12 = const 32_u32;              // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16
-          StorageLive(_13);                // scope 8 at $DIR/const_debuginfo.rs:+13:19: +13:22
-          _13 = const 32_u32;              // scope 8 at $DIR/const_debuginfo.rs:+13:19: +13:22
           _11 = const 64_u32;              // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:22
-          StorageDead(_13);                // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22
-          StorageDead(_12);                // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22
           StorageDead(_11);                // scope 8 at $DIR/const_debuginfo.rs:+14:1: +14:2
-          StorageDead(_17);                // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2
-          StorageDead(_18);                // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2
           StorageDead(_10);                // scope 6 at $DIR/const_debuginfo.rs:+14:1: +14:2
           StorageDead(_14);                // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
           StorageDead(_15);                // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
index f54577259431da796336b9c52d937c479de6e213..4dc98f8567402fc05bc9f2261f68ffce550cf7e4 100644 (file)
@@ -17,7 +17,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/const_goto_storage.rs:+1:9: +1:12
 -         StorageLive(_2);                 // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23
--         Deinit(_2);                      // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23
+-         _2 = ();                         // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23
 -         StorageLive(_3);                 // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10
 -         StorageLive(_4);                 // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76
 -         StorageLive(_5);                 // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52
diff --git a/tests/mir-opt/const_prop/aggregate.foo.ConstProp.diff b/tests/mir-opt/const_prop/aggregate.foo.ConstProp.diff
new file mode 100644 (file)
index 0000000..6ac460d
--- /dev/null
@@ -0,0 +1,55 @@
+- // MIR for `foo` before ConstProp
++ // MIR for `foo` after ConstProp
+  
+  fn foo(_1: u8) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/aggregate.rs:+0:8: +0:9
+      let mut _0: ();                      // return place in scope 0 at $DIR/aggregate.rs:+0:15: +0:15
+      let _2: i32;                         // in scope 0 at $DIR/aggregate.rs:+2:9: +2:14
+      let mut _3: i32;                     // in scope 0 at $DIR/aggregate.rs:+2:17: +2:25
+      let mut _4: (i32, u8);               // in scope 0 at $DIR/aggregate.rs:+2:17: +2:23
+      let mut _5: u8;                      // in scope 0 at $DIR/aggregate.rs:+2:21: +2:22
+      let mut _7: i32;                     // in scope 0 at $DIR/aggregate.rs:+3:18: +3:26
+      let mut _8: (u8, i32);               // in scope 0 at $DIR/aggregate.rs:+3:18: +3:24
+      let mut _9: u8;                      // in scope 0 at $DIR/aggregate.rs:+3:19: +3:20
+      scope 1 {
+          debug first => _2;               // in scope 1 at $DIR/aggregate.rs:+2:9: +2:14
+          let _6: i32;                     // in scope 1 at $DIR/aggregate.rs:+3:9: +3:15
+          scope 2 {
+              debug second => _6;          // in scope 2 at $DIR/aggregate.rs:+3:9: +3:15
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/aggregate.rs:+2:9: +2:14
+          StorageLive(_3);                 // scope 0 at $DIR/aggregate.rs:+2:17: +2:25
+          StorageLive(_4);                 // scope 0 at $DIR/aggregate.rs:+2:17: +2:23
+          StorageLive(_5);                 // scope 0 at $DIR/aggregate.rs:+2:21: +2:22
+          _5 = _1;                         // scope 0 at $DIR/aggregate.rs:+2:21: +2:22
+          _4 = (const 0_i32, move _5);     // scope 0 at $DIR/aggregate.rs:+2:17: +2:23
+          StorageDead(_5);                 // scope 0 at $DIR/aggregate.rs:+2:22: +2:23
+-         _3 = (_4.0: i32);                // scope 0 at $DIR/aggregate.rs:+2:17: +2:25
+-         _2 = Add(move _3, const 1_i32);  // scope 0 at $DIR/aggregate.rs:+2:17: +2:29
++         _3 = const 0_i32;                // scope 0 at $DIR/aggregate.rs:+2:17: +2:25
++         _2 = const 1_i32;                // scope 0 at $DIR/aggregate.rs:+2:17: +2:29
+          StorageDead(_3);                 // scope 0 at $DIR/aggregate.rs:+2:28: +2:29
+          StorageDead(_4);                 // scope 0 at $DIR/aggregate.rs:+2:29: +2:30
+          StorageLive(_6);                 // scope 1 at $DIR/aggregate.rs:+3:9: +3:15
+          StorageLive(_7);                 // scope 1 at $DIR/aggregate.rs:+3:18: +3:26
+          StorageLive(_8);                 // scope 1 at $DIR/aggregate.rs:+3:18: +3:24
+          StorageLive(_9);                 // scope 1 at $DIR/aggregate.rs:+3:19: +3:20
+          _9 = _1;                         // scope 1 at $DIR/aggregate.rs:+3:19: +3:20
+          _8 = (move _9, const 1_i32);     // scope 1 at $DIR/aggregate.rs:+3:18: +3:24
+          StorageDead(_9);                 // scope 1 at $DIR/aggregate.rs:+3:23: +3:24
+-         _7 = (_8.1: i32);                // scope 1 at $DIR/aggregate.rs:+3:18: +3:26
+-         _6 = Add(move _7, const 2_i32);  // scope 1 at $DIR/aggregate.rs:+3:18: +3:30
++         _7 = const 1_i32;                // scope 1 at $DIR/aggregate.rs:+3:18: +3:26
++         _6 = const 3_i32;                // scope 1 at $DIR/aggregate.rs:+3:18: +3:30
+          StorageDead(_7);                 // scope 1 at $DIR/aggregate.rs:+3:29: +3:30
+          StorageDead(_8);                 // scope 1 at $DIR/aggregate.rs:+3:30: +3:31
+          _0 = const ();                   // scope 0 at $DIR/aggregate.rs:+0:15: +4:2
+          StorageDead(_6);                 // scope 1 at $DIR/aggregate.rs:+4:1: +4:2
+          StorageDead(_2);                 // scope 0 at $DIR/aggregate.rs:+4:1: +4:2
+          return;                          // scope 0 at $DIR/aggregate.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/const_prop/aggregate.foo.PreCodegen.after.mir b/tests/mir-opt/const_prop/aggregate.foo.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..2ef6d74
--- /dev/null
@@ -0,0 +1,49 @@
+// MIR for `foo` after PreCodegen
+
+fn foo(_1: u8) -> () {
+    debug x => _1;                       // in scope 0 at $DIR/aggregate.rs:+0:8: +0:9
+    let mut _0: ();                      // return place in scope 0 at $DIR/aggregate.rs:+0:15: +0:15
+    let _2: i32;                         // in scope 0 at $DIR/aggregate.rs:+2:9: +2:14
+    let mut _3: i32;                     // in scope 0 at $DIR/aggregate.rs:+2:17: +2:25
+    let mut _4: (i32, u8);               // in scope 0 at $DIR/aggregate.rs:+2:17: +2:23
+    let mut _5: u8;                      // in scope 0 at $DIR/aggregate.rs:+2:21: +2:22
+    let mut _7: i32;                     // in scope 0 at $DIR/aggregate.rs:+3:18: +3:26
+    let mut _8: (u8, i32);               // in scope 0 at $DIR/aggregate.rs:+3:18: +3:24
+    let mut _9: u8;                      // in scope 0 at $DIR/aggregate.rs:+3:19: +3:20
+    scope 1 {
+        debug first => _2;               // in scope 1 at $DIR/aggregate.rs:+2:9: +2:14
+        let _6: i32;                     // in scope 1 at $DIR/aggregate.rs:+3:9: +3:15
+        scope 2 {
+            debug second => _6;          // in scope 2 at $DIR/aggregate.rs:+3:9: +3:15
+        }
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/aggregate.rs:+2:9: +2:14
+        StorageLive(_3);                 // scope 0 at $DIR/aggregate.rs:+2:17: +2:25
+        StorageLive(_4);                 // scope 0 at $DIR/aggregate.rs:+2:17: +2:23
+        StorageLive(_5);                 // scope 0 at $DIR/aggregate.rs:+2:21: +2:22
+        _5 = _1;                         // scope 0 at $DIR/aggregate.rs:+2:21: +2:22
+        _4 = (const 0_i32, move _5);     // scope 0 at $DIR/aggregate.rs:+2:17: +2:23
+        StorageDead(_5);                 // scope 0 at $DIR/aggregate.rs:+2:22: +2:23
+        _3 = const 0_i32;                // scope 0 at $DIR/aggregate.rs:+2:17: +2:25
+        _2 = const 1_i32;                // scope 0 at $DIR/aggregate.rs:+2:17: +2:29
+        StorageDead(_3);                 // scope 0 at $DIR/aggregate.rs:+2:28: +2:29
+        StorageDead(_4);                 // scope 0 at $DIR/aggregate.rs:+2:29: +2:30
+        StorageLive(_6);                 // scope 1 at $DIR/aggregate.rs:+3:9: +3:15
+        StorageLive(_7);                 // scope 1 at $DIR/aggregate.rs:+3:18: +3:26
+        StorageLive(_8);                 // scope 1 at $DIR/aggregate.rs:+3:18: +3:24
+        StorageLive(_9);                 // scope 1 at $DIR/aggregate.rs:+3:19: +3:20
+        _9 = _1;                         // scope 1 at $DIR/aggregate.rs:+3:19: +3:20
+        _8 = (move _9, const 1_i32);     // scope 1 at $DIR/aggregate.rs:+3:18: +3:24
+        StorageDead(_9);                 // scope 1 at $DIR/aggregate.rs:+3:23: +3:24
+        _7 = const 1_i32;                // scope 1 at $DIR/aggregate.rs:+3:18: +3:26
+        _6 = const 3_i32;                // scope 1 at $DIR/aggregate.rs:+3:18: +3:30
+        StorageDead(_7);                 // scope 1 at $DIR/aggregate.rs:+3:29: +3:30
+        StorageDead(_8);                 // scope 1 at $DIR/aggregate.rs:+3:30: +3:31
+        _0 = const ();                   // scope 0 at $DIR/aggregate.rs:+0:15: +4:2
+        StorageDead(_6);                 // scope 1 at $DIR/aggregate.rs:+4:1: +4:2
+        StorageDead(_2);                 // scope 0 at $DIR/aggregate.rs:+4:1: +4:2
+        return;                          // scope 0 at $DIR/aggregate.rs:+4:2: +4:2
+    }
+}
index 04378dbf374d9d74e312363997242227ebbc1dbc..f6e58955b4f607bda88d14caaad97155edd15853 100644 (file)
@@ -3,9 +3,11 @@
   
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/aggregate.rs:+0:11: +0:11
-      let _1: i32;                         // in scope 0 at $DIR/aggregate.rs:+1:9: +1:10
-      let mut _2: i32;                     // in scope 0 at $DIR/aggregate.rs:+1:13: +1:24
-      let mut _3: (i32, i32, i32);         // in scope 0 at $DIR/aggregate.rs:+1:13: +1:22
+      let _1: u8;                          // in scope 0 at $DIR/aggregate.rs:+1:9: +1:10
+      let mut _2: u8;                      // in scope 0 at $DIR/aggregate.rs:+1:13: +1:24
+      let mut _3: (i32, u8, i32);          // in scope 0 at $DIR/aggregate.rs:+1:13: +1:22
+      let _4: ();                          // in scope 0 at $DIR/aggregate.rs:+2:5: +2:11
+      let mut _5: u8;                      // in scope 0 at $DIR/aggregate.rs:+2:9: +2:10
       scope 1 {
           debug x => _1;                   // in scope 1 at $DIR/aggregate.rs:+1:9: +1:10
       }
           StorageLive(_1);                 // scope 0 at $DIR/aggregate.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 0 at $DIR/aggregate.rs:+1:13: +1:24
           StorageLive(_3);                 // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
-          Deinit(_3);                      // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
-          (_3.0: i32) = const 0_i32;       // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
-          (_3.1: i32) = const 1_i32;       // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
-          (_3.2: i32) = const 2_i32;       // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
--         _2 = (_3.1: i32);                // scope 0 at $DIR/aggregate.rs:+1:13: +1:24
--         _1 = Add(move _2, const 0_i32);  // scope 0 at $DIR/aggregate.rs:+1:13: +1:28
-+         _2 = const 1_i32;                // scope 0 at $DIR/aggregate.rs:+1:13: +1:24
-+         _1 = const 1_i32;                // scope 0 at $DIR/aggregate.rs:+1:13: +1:28
+          _3 = (const 0_i32, const 1_u8, const 2_i32); // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
+-         _2 = (_3.1: u8);                 // scope 0 at $DIR/aggregate.rs:+1:13: +1:24
+-         _1 = Add(move _2, const 0_u8);   // scope 0 at $DIR/aggregate.rs:+1:13: +1:28
++         _2 = const 1_u8;                 // scope 0 at $DIR/aggregate.rs:+1:13: +1:24
++         _1 = const 1_u8;                 // scope 0 at $DIR/aggregate.rs:+1:13: +1:28
           StorageDead(_2);                 // scope 0 at $DIR/aggregate.rs:+1:27: +1:28
           StorageDead(_3);                 // scope 0 at $DIR/aggregate.rs:+1:28: +1:29
-          _0 = const ();                   // scope 0 at $DIR/aggregate.rs:+0:11: +2:2
-          StorageDead(_1);                 // scope 0 at $DIR/aggregate.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/aggregate.rs:+2:2: +2:2
+          StorageLive(_4);                 // scope 1 at $DIR/aggregate.rs:+2:5: +2:11
+          StorageLive(_5);                 // scope 1 at $DIR/aggregate.rs:+2:9: +2:10
+-         _5 = _1;                         // scope 1 at $DIR/aggregate.rs:+2:9: +2:10
++         _5 = const 1_u8;                 // scope 1 at $DIR/aggregate.rs:+2:9: +2:10
+          _4 = foo(move _5) -> bb1;        // scope 1 at $DIR/aggregate.rs:+2:5: +2:11
+                                           // mir::Constant
+                                           // + span: $DIR/aggregate.rs:8:5: 8:8
+                                           // + literal: Const { ty: fn(u8) {foo}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageDead(_5);                 // scope 1 at $DIR/aggregate.rs:+2:10: +2:11
+          StorageDead(_4);                 // scope 1 at $DIR/aggregate.rs:+2:11: +2:12
+          _0 = const ();                   // scope 0 at $DIR/aggregate.rs:+0:11: +3:2
+          StorageDead(_1);                 // scope 0 at $DIR/aggregate.rs:+3:1: +3:2
+          return;                          // scope 0 at $DIR/aggregate.rs:+3:2: +3:2
       }
   }
   
index cfc9a72e3b2287d4a4595a679a93200a796e31a6..4706af92cba982460cb000b76ce91829be11aa13 100644 (file)
@@ -2,9 +2,11 @@
 
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/aggregate.rs:+0:11: +0:11
-    let _1: i32;                         // in scope 0 at $DIR/aggregate.rs:+1:9: +1:10
-    let mut _2: i32;                     // in scope 0 at $DIR/aggregate.rs:+1:13: +1:24
-    let mut _3: (i32, i32, i32);         // in scope 0 at $DIR/aggregate.rs:+1:13: +1:22
+    let _1: u8;                          // in scope 0 at $DIR/aggregate.rs:+1:9: +1:10
+    let mut _2: u8;                      // in scope 0 at $DIR/aggregate.rs:+1:13: +1:24
+    let mut _3: (i32, u8, i32);          // in scope 0 at $DIR/aggregate.rs:+1:13: +1:22
+    let _4: ();                          // in scope 0 at $DIR/aggregate.rs:+2:5: +2:11
+    let mut _5: u8;                      // in scope 0 at $DIR/aggregate.rs:+2:9: +2:10
     scope 1 {
         debug x => _1;                   // in scope 1 at $DIR/aggregate.rs:+1:9: +1:10
     }
@@ -13,16 +15,25 @@ fn main() -> () {
         StorageLive(_1);                 // scope 0 at $DIR/aggregate.rs:+1:9: +1:10
         StorageLive(_2);                 // scope 0 at $DIR/aggregate.rs:+1:13: +1:24
         StorageLive(_3);                 // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
-        Deinit(_3);                      // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
-        (_3.0: i32) = const 0_i32;       // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
-        (_3.1: i32) = const 1_i32;       // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
-        (_3.2: i32) = const 2_i32;       // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
-        _2 = const 1_i32;                // scope 0 at $DIR/aggregate.rs:+1:13: +1:24
-        _1 = const 1_i32;                // scope 0 at $DIR/aggregate.rs:+1:13: +1:28
+        _3 = (const 0_i32, const 1_u8, const 2_i32); // scope 0 at $DIR/aggregate.rs:+1:13: +1:22
+        _2 = const 1_u8;                 // scope 0 at $DIR/aggregate.rs:+1:13: +1:24
+        _1 = const 1_u8;                 // scope 0 at $DIR/aggregate.rs:+1:13: +1:28
         StorageDead(_2);                 // scope 0 at $DIR/aggregate.rs:+1:27: +1:28
         StorageDead(_3);                 // scope 0 at $DIR/aggregate.rs:+1:28: +1:29
-        _0 = const ();                   // scope 0 at $DIR/aggregate.rs:+0:11: +2:2
-        StorageDead(_1);                 // scope 0 at $DIR/aggregate.rs:+2:1: +2:2
-        return;                          // scope 0 at $DIR/aggregate.rs:+2:2: +2:2
+        StorageLive(_4);                 // scope 1 at $DIR/aggregate.rs:+2:5: +2:11
+        StorageLive(_5);                 // scope 1 at $DIR/aggregate.rs:+2:9: +2:10
+        _5 = const 1_u8;                 // scope 1 at $DIR/aggregate.rs:+2:9: +2:10
+        _4 = foo(move _5) -> bb1;        // scope 1 at $DIR/aggregate.rs:+2:5: +2:11
+                                         // mir::Constant
+                                         // + span: $DIR/aggregate.rs:8:5: 8:8
+                                         // + literal: Const { ty: fn(u8) {foo}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        StorageDead(_5);                 // scope 1 at $DIR/aggregate.rs:+2:10: +2:11
+        StorageDead(_4);                 // scope 1 at $DIR/aggregate.rs:+2:11: +2:12
+        _0 = const ();                   // scope 0 at $DIR/aggregate.rs:+0:11: +3:2
+        StorageDead(_1);                 // scope 0 at $DIR/aggregate.rs:+3:1: +3:2
+        return;                          // scope 0 at $DIR/aggregate.rs:+3:2: +3:2
     }
 }
index 6a3080384daf4fb0e285d412d331ef59ac258e40..aa123b7a8664dfb839013275b03e6b92f55d22f7 100644 (file)
@@ -5,4 +5,13 @@
 // EMIT_MIR aggregate.main.PreCodegen.after.mir
 fn main() {
     let x = (0, 1, 2).1 + 0;
+    foo(x);
+}
+
+// EMIT_MIR aggregate.foo.ConstProp.diff
+// EMIT_MIR aggregate.foo.PreCodegen.after.mir
+fn foo(x: u8) {
+    // Verify that we still propagate if part of the aggregate is not known.
+    let first = (0, x).0 + 1;
+    let second = (x, 1).1 + 2;
 }
index b4dccecc67265e74d5191fa6930acf8b1ee8e307..b9a10704be0dcd6914b0349e38a43d88e8dff653 100644 (file)
           StorageLive(_1);                 // scope 0 at $DIR/discriminant.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 0 at $DIR/discriminant.rs:+1:13: +1:64
           StorageLive(_3);                 // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
-          Deinit(_3);                      // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
-          ((_3 as Some).0: bool) = const true; // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
-          discriminant(_3) = 1;            // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
+-         _3 = Option::<bool>::Some(const true); // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
 -         _4 = discriminant(_3);           // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
 -         switchInt(move _4) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
++         _3 = const Option::<bool>::Some(true); // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
++                                          // mir::Constant
++                                          // + span: $DIR/discriminant.rs:12:34: 12:44
++                                          // + literal: Const { ty: Option<bool>, val: Value(Scalar(0x01)) }
 +         _4 = const 1_isize;              // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
 +         switchInt(const 1_isize) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
       }
   
       bb1: {
-          switchInt(((_3 as Some).0: bool)) -> [0: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
+-         switchInt(((_3 as Some).0: bool)) -> [0: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
++         switchInt(const true) -> [0: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
       }
   
       bb2: {
index b4dccecc67265e74d5191fa6930acf8b1ee8e307..b9a10704be0dcd6914b0349e38a43d88e8dff653 100644 (file)
           StorageLive(_1);                 // scope 0 at $DIR/discriminant.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 0 at $DIR/discriminant.rs:+1:13: +1:64
           StorageLive(_3);                 // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
-          Deinit(_3);                      // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
-          ((_3 as Some).0: bool) = const true; // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
-          discriminant(_3) = 1;            // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
+-         _3 = Option::<bool>::Some(const true); // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
 -         _4 = discriminant(_3);           // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
 -         switchInt(move _4) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
++         _3 = const Option::<bool>::Some(true); // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
++                                          // mir::Constant
++                                          // + span: $DIR/discriminant.rs:12:34: 12:44
++                                          // + literal: Const { ty: Option<bool>, val: Value(Scalar(0x01)) }
 +         _4 = const 1_isize;              // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
 +         switchInt(const 1_isize) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
       }
   
       bb1: {
-          switchInt(((_3 as Some).0: bool)) -> [0: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
+-         switchInt(((_3 as Some).0: bool)) -> [0: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
++         switchInt(const true) -> [0: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
       }
   
       bb2: {
index 6c4757c1a81036cc1102860e69edde66bc79d750..4f056dd85e3f7999faa7851adeb2e15c52d1ad77 100644 (file)
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/invalid_constant.rs:+6:9: +6:22
           StorageLive(_2);                 // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63
-          Deinit(_2);                      // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63
-          (_2.0: u32) = const 1114113_u32; // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63
+          _2 = InvalidChar { int: const 1114113_u32 }; // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63
 -         _1 = (_2.1: char);               // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:67
 +         _1 = const {transmute(0x00110001): char}; // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:67
           StorageDead(_2);                 // scope 0 at $DIR/invalid_constant.rs:+6:69: +6:70
           StorageLive(_3);                 // scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
           StorageLive(_4);                 // scope 1 at $DIR/invalid_constant.rs:+13:25: +13:59
           StorageLive(_5);                 // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
-          Deinit(_5);                      // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
-          (_5.0: u32) = const 4_u32;       // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
+          _5 = InvalidTag { int: const 4_u32 }; // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
 -         _4 = (_5.1: E);                  // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57
 -         _3 = [move _4];                  // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60
 +         _4 = const Scalar(0x00000004): E; // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57
index 488e772d0ea8b3c735129c3db20d0b71a0aec860..964dd3080749abdd9a20c9efe82196cb3f025111 100644 (file)
@@ -5,13 +5,14 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/issue_66971.rs:+0:11: +0:11
       let _1: ();                          // in scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
       let mut _2: ((), u8, u8);            // in scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
+      let mut _3: ();                      // in scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
           StorageLive(_2);                 // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
-          Deinit(_2);                      // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
-          (_2.1: u8) = const 0_u8;         // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
-          (_2.2: u8) = const 0_u8;         // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
+          StorageLive(_3);                 // scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
+          _2 = (move _3, const 0_u8, const 0_u8); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
+          StorageDead(_3);                 // scope 0 at $DIR/issue_66971.rs:+1:21: +1:22
           _1 = encode(move _2) -> bb1;     // scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
                                            // mir::Constant
                                            // + span: $DIR/issue_66971.rs:17:5: 17:11
index cd53048597b82083e9e58e0e8770c24ac7b6af17..a631cb310904ba8d34699681ea8c015dec276c42 100644 (file)
           StorageLive(_1);                 // scope 0 at $DIR/issue_67019.rs:+1:5: +1:20
           StorageLive(_2);                 // scope 0 at $DIR/issue_67019.rs:+1:10: +1:19
           StorageLive(_3);                 // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
-          Deinit(_3);                      // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
-          (_3.0: u8) = const 1_u8;         // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
-          (_3.1: u8) = const 2_u8;         // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
-          Deinit(_2);                      // scope 0 at $DIR/issue_67019.rs:+1:10: +1:19
--         (_2.0: (u8, u8)) = move _3;      // scope 0 at $DIR/issue_67019.rs:+1:10: +1:19
-+         (_2.0: (u8, u8)) = const (1_u8, 2_u8); // scope 0 at $DIR/issue_67019.rs:+1:10: +1:19
+-         _3 = (const 1_u8, const 2_u8);   // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
++         _3 = const (1_u8, 2_u8);         // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
+          _2 = (move _3,);                 // scope 0 at $DIR/issue_67019.rs:+1:10: +1:19
           StorageDead(_3);                 // scope 0 at $DIR/issue_67019.rs:+1:18: +1:19
           _1 = test(move _2) -> bb1;       // scope 0 at $DIR/issue_67019.rs:+1:5: +1:20
                                            // mir::Constant
index f6bf522065bac59ff89dee8edb63e5cc4785ab90..d088c4f662b7b21ab64582b7507623fb7a124bd1 100644 (file)
@@ -3,26 +3,27 @@
   
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/mutable_variable_aggregate.rs:+0:11: +0:11
-      let mut _1: (i32, i32);              // in scope 0 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14
+      let mut _3: i32;                     // in scope 0 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14
+      let mut _4: i32;                     // in scope 0 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14
       scope 1 {
-          debug x => _1;                   // in scope 1 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14
-          let _2: (i32, i32);              // in scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10
+          debug x => (i32, i32){ .0 => _3, .1 => _4, }; // in scope 1 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14
+          let _1: i32;                     // in scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10
+          let _2: i32;                     // in scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10
           scope 2 {
-              debug y => _2;               // in scope 2 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10
+              debug y => (i32, i32){ .0 => _3, .1 => _2, }; // in scope 2 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10
           }
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14
-          Deinit(_1);                      // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:17: +1:25
-          (_1.0: i32) = const 42_i32;      // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:17: +1:25
-          (_1.1: i32) = const 43_i32;      // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:17: +1:25
-          (_1.1: i32) = const 99_i32;      // scope 1 at $DIR/mutable_variable_aggregate.rs:+2:5: +2:13
+          StorageLive(_4);                 // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14
+          _3 = const 42_i32;               // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:17: +1:25
+          _4 = const 43_i32;               // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:17: +1:25
+          _4 = const 99_i32;               // scope 1 at $DIR/mutable_variable_aggregate.rs:+2:5: +2:13
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10
--         _2 = _1;                         // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14
-+         _2 = const (42_i32, 99_i32);     // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14
+-         _2 = _4;                         // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14
++         _2 = const 99_i32;               // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14
           StorageDead(_2);                 // scope 1 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2
-          StorageDead(_1);                 // scope 0 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2
+          StorageDead(_4);                 // scope 0 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/mutable_variable_aggregate.rs:+4:2: +4:2
       }
   }
index 213a70227d876324abbc04286d9971d128596929..134f0c080bf8118d8a3c26ec452720bd09c7c72e 100644 (file)
@@ -9,24 +9,26 @@
           let _2: &mut (i32, i32);         // in scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:+2:9: +2:10
           scope 2 {
               debug z => _2;               // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+2:9: +2:10
-              let _3: (i32, i32);          // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10
+              let _3: i32;                 // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10
+              let _4: i32;                 // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10
               scope 3 {
-                  debug y => _3;           // in scope 3 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10
+                  debug y => (i32, i32){ .0 => _3, .1 => _4, }; // in scope 3 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10
               }
           }
       }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+1:9: +1:14
-          Deinit(_1);                      // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+1:17: +1:25
-          (_1.0: i32) = const 42_i32;      // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+1:17: +1:25
-          (_1.1: i32) = const 43_i32;      // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+1:17: +1:25
+          _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+1:17: +1:25
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:+2:9: +2:10
           _2 = &mut _1;                    // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:+2:13: +2:19
           ((*_2).1: i32) = const 99_i32;   // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+3:5: +3:13
           StorageLive(_3);                 // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10
-          _3 = _1;                         // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:13: +4:14
+          StorageLive(_4);                 // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10
+          _3 = (_1.0: i32);                // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:13: +4:14
+          _4 = (_1.1: i32);                // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:13: +4:14
           StorageDead(_3);                 // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2
+          StorageDead(_4);                 // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2
           StorageDead(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2
           StorageDead(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:2: +5:2
index c3f77b960a2dc1b2bccaf4c1114051b436e5310e..4010dd6c6d0d8518a55625090c90d496455f41b9 100644 (file)
@@ -16,7 +16,7 @@
                   debug y => _3;           // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
                   let _4: i32;             // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
                   scope 4 {
-                      debug z => _4;       // in scope 4 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
+                      debug z => _5;       // in scope 4 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
                   }
               }
           }
       }
   
       bb1: {
-          StorageLive(_5);                 // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
           StorageLive(_6);                 // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
-          Deinit(_5);                      // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
-          Deinit(_6);                      // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
           _5 = const 1_i32;                // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
           _6 = const 2_i32;                // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
           StorageLive(_2);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
           StorageDead(_2);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
           StorageLive(_3);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
           _3 = _6;                         // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16
-          StorageLive(_4);                 // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
--         _4 = _5;                         // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
-+         _4 = const 1_i32;                // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
-          StorageDead(_4);                 // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
           StorageDead(_3);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
-          StorageDead(_5);                 // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
           StorageDead(_6);                 // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
           StorageDead(_1);                 // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
           return;                          // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:2: +6:2
index 7c7aeac4c451bf0aa3c8a5d4c169ba9ba0c9accf..691aa01a564080d31e64c2000fbbdff0394a91b4 100644 (file)
@@ -17,7 +17,7 @@
               debug y => _3;               // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
               let _8: u32;                 // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
               scope 3 {
-                  debug z => _8;           // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
+                  debug z => _9;           // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
               }
           }
       }
 +         _3 = const 3_i32;                // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
           StorageDead(_5);                 // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
           StorageDead(_4);                 // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
-          StorageLive(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
-          StorageLive(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
-          Deinit(_9);                      // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
           _9 = const 42_u32;               // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
--         _8 = _9;                         // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
-+         _8 = const 42_u32;               // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
-          StorageDead(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
-          StorageDead(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
           StorageDead(_3);                 // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
           StorageDead(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
index 7c7aeac4c451bf0aa3c8a5d4c169ba9ba0c9accf..691aa01a564080d31e64c2000fbbdff0394a91b4 100644 (file)
@@ -17,7 +17,7 @@
               debug y => _3;               // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
               let _8: u32;                 // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
               scope 3 {
-                  debug z => _8;           // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
+                  debug z => _9;           // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
               }
           }
       }
 +         _3 = const 3_i32;                // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
           StorageDead(_5);                 // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
           StorageDead(_4);                 // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
-          StorageLive(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
-          StorageLive(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
-          Deinit(_9);                      // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
           _9 = const 42_u32;               // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
--         _8 = _9;                         // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
-+         _8 = const 42_u32;               // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
-          StorageDead(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
-          StorageDead(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
           StorageDead(_3);                 // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
           StorageDead(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
index 9db87cfc879bbee9fc421a8ba345009ed1acf2ed..81cfd22db6c5078732613b9243f7e4dfacc22d2a 100644 (file)
@@ -3,12 +3,12 @@
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11
     let _1: i32;                         // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
+    let mut _3: u32;                     // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
     scope 1 {
         debug x => _1;                   // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
         let _2: i32;                     // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
         scope 2 {
             debug y => _2;               // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
-            let _3: u32;                 // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
             scope 3 {
                 debug z => _3;           // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
             }
@@ -18,8 +18,6 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
         StorageLive(_2);                 // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
-        StorageLive(_3);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
-        StorageDead(_3);                 // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
         StorageDead(_2);                 // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
         StorageDead(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
         return;                          // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
index 9db87cfc879bbee9fc421a8ba345009ed1acf2ed..81cfd22db6c5078732613b9243f7e4dfacc22d2a 100644 (file)
@@ -3,12 +3,12 @@
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11
     let _1: i32;                         // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
+    let mut _3: u32;                     // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
     scope 1 {
         debug x => _1;                   // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
         let _2: i32;                     // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
         scope 2 {
             debug y => _2;               // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
-            let _3: u32;                 // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
             scope 3 {
                 debug z => _3;           // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
             }
@@ -18,8 +18,6 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
         StorageLive(_2);                 // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
-        StorageLive(_3);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
-        StorageDead(_3);                 // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
         StorageDead(_2);                 // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
         StorageDead(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
         return;                          // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
index 3f9f3b2eac7163c398b49cd36905a8ef5eab870f..98cd020dade4ba0665d1836e53e3de6ef1d41030 100644 (file)
           StorageDead(_4);                 // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
           StorageLive(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
 -         StorageLive(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
--         Deinit(_9);                      // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
--         (_9.0: u32) = const 12_u32;      // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
--         (_9.1: u32) = const 42_u32;      // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+-         _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
 -         _8 = (_9.1: u32);                // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
 -         StorageDead(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
 +         StorageLive(_10);                // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
 +         StorageLive(_11);                // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
-+         Deinit(_10);                     // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
-+         Deinit(_11);                     // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
++         nop;                             // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
 +         _10 = const 12_u32;              // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
 +         _11 = const 42_u32;              // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
++         nop;                             // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
 +         _8 = _11;                        // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
 +         StorageDead(_10);                // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
 +         StorageDead(_11);                // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
++         nop;                             // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
           nop;                             // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2
           StorageDead(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
           StorageDead(_3);                 // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
index 3f9f3b2eac7163c398b49cd36905a8ef5eab870f..98cd020dade4ba0665d1836e53e3de6ef1d41030 100644 (file)
           StorageDead(_4);                 // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35
           StorageLive(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
 -         StorageLive(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
--         Deinit(_9);                      // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
--         (_9.0: u32) = const 12_u32;      // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
--         (_9.1: u32) = const 42_u32;      // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+-         _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
 -         _8 = (_9.1: u32);                // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
 -         StorageDead(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
 +         StorageLive(_10);                // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
 +         StorageLive(_11);                // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
-+         Deinit(_10);                     // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
-+         Deinit(_11);                     // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
++         nop;                             // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
 +         _10 = const 12_u32;              // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
 +         _11 = const 42_u32;              // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
++         nop;                             // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
 +         _8 = _11;                        // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
 +         StorageDead(_10);                // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
 +         StorageDead(_11);                // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
++         nop;                             // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39
           nop;                             // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2
           StorageDead(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
           StorageDead(_3);                 // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
index d926b9df73317fe6ffbcaaec89d09ad4b471fd48..002e914e8fa165b75ec467e5ddc10d15522fb26e 100644 (file)
@@ -3,12 +3,12 @@
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11
     let _1: i32;                         // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
+    let mut _3: u32;                     // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
     scope 1 {
         debug x => _1;                   // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
         let _2: i32;                     // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
         scope 2 {
             debug y => _2;               // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
-            let _3: u32;                 // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
             scope 3 {
                 debug z => _3;           // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
             }
@@ -18,8 +18,6 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
         StorageLive(_2);                 // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
-        StorageLive(_3);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
-        StorageDead(_3);                 // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
         StorageDead(_2);                 // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
         StorageDead(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
         return;                          // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
index d926b9df73317fe6ffbcaaec89d09ad4b471fd48..002e914e8fa165b75ec467e5ddc10d15522fb26e 100644 (file)
@@ -3,12 +3,12 @@
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11
     let _1: i32;                         // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
+    let mut _3: u32;                     // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
     scope 1 {
         debug x => _1;                   // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
         let _2: i32;                     // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
         scope 2 {
             debug y => _2;               // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
-            let _3: u32;                 // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
             scope 3 {
                 debug z => _3;           // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
             }
@@ -18,8 +18,6 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10
         StorageLive(_2);                 // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
-        StorageLive(_3);                 // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10
-        StorageDead(_3);                 // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
         StorageDead(_2);                 // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
         StorageDead(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2
         return;                          // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2
index e4c92b617c6a31180d3888899e8b05ec6d046f96..270a1ccf560f1e5de0b078884a2e1bd0d5683021 100644 (file)
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/tuple_literal_propagation.rs:+1:9: +1:10
-          Deinit(_1);                      // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
-          (_1.0: u32) = const 1_u32;       // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
-          (_1.1: u32) = const 2_u32;       // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
+-         _1 = (const 1_u32, const 2_u32); // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
++         _1 = const (1_u32, 2_u32);       // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
           StorageLive(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
-          StorageLive(_3);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:13: +3:14
--         _3 = _1;                         // scope 1 at $DIR/tuple_literal_propagation.rs:+3:13: +3:14
-+         _3 = const (1_u32, 2_u32);       // scope 1 at $DIR/tuple_literal_propagation.rs:+3:13: +3:14
-          _2 = consume(move _3) -> bb1;    // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
+          _2 = consume(_1) -> bb1;         // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
                                            // mir::Constant
                                            // + span: $DIR/tuple_literal_propagation.rs:5:5: 5:12
                                            // + literal: Const { ty: fn((u32, u32)) {consume}, val: Value(<ZST>) }
       }
   
       bb1: {
-          StorageDead(_3);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:14: +3:15
           StorageDead(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:15: +3:16
-          StorageDead(_1);                 // scope 0 at $DIR/tuple_literal_propagation.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/tuple_literal_propagation.rs:+4:2: +4:2
       }
   }
index b6b542fb79436d3ce1b3b8dacdb4202e57e0aa01..def9fc6428fb63e8f02cd104db629c54aaa9c90f 100644 (file)
@@ -19,8 +19,8 @@
   
       bb0: {
           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
+-         _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
++         _1 = const (1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
           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
index e43735fd9e145057c6ea8395c378fc5aeb5e2657..b54c10a140f2cb30b529fa34c4929f1bcb634aab 100644 (file)
@@ -16,8 +16,8 @@
   
       bb0: {
           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
+-         _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
++         _1 = const (1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
           StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:+2:6: +2:14
           _2 = &mut (_1.0: i32);           // scope 1 at $DIR/const_prop_miscompile.rs:+2:6: +2:14
           (*_2) = const 5_i32;             // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +2:18
index 28ba651ad4ae0e2bf7706f4c0619dafc150f998b..97d0a01e00bc4fd725769dfb1cc601b264026b22 100644 (file)
@@ -57,9 +57,7 @@
   
       bb1: {
           StorageDead(_6);                 // scope 2 at $DIR/issue_107511.rs:+6:23: +6:24
-          Deinit(_4);                      // scope 2 at $DIR/issue_107511.rs:+6:14: +6:24
-          (_4.0: usize) = const 0_usize;   // scope 2 at $DIR/issue_107511.rs:+6:14: +6:24
-          (_4.1: usize) = move _5;         // scope 2 at $DIR/issue_107511.rs:+6:14: +6:24
+          _4 = std::ops::Range::<usize> { start: const 0_usize, end: move _5 }; // scope 2 at $DIR/issue_107511.rs:+6:14: +6:24
           StorageDead(_5);                 // scope 2 at $DIR/issue_107511.rs:+6:23: +6:24
           _3 = <std::ops::Range<usize> as IntoIterator>::into_iter(move _4) -> bb2; // scope 2 at $DIR/issue_107511.rs:+6:14: +6:24
                                            // mir::Constant
diff --git a/tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff b/tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff
new file mode 100644 (file)
index 0000000..02308be
--- /dev/null
@@ -0,0 +1,31 @@
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+  
+  fn f(_1: Foo) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/move_projection.rs:+0:17: +0:21
+      let mut _2: Foo;                     // 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
+  
+      bb0: {
+-         _2 = _1;                         // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+-         _3 = move (_2.0: u8);            // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+-         _0 = opaque::<Foo>(move _1) -> bb1; // scope 0 at $DIR/move_projection.rs:+6:13: +6:44
++         _3 = (_1.0: u8);                 // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
++         _0 = opaque::<Foo>(_1) -> bb1;   // scope 0 at $DIR/move_projection.rs:+6:13: +6:44
+                                           // mir::Constant
+                                           // + span: $DIR/move_projection.rs:19:28: 19:34
+                                           // + literal: Const { ty: fn(Foo) -> bool {opaque::<Foo>}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          _0 = opaque::<u8>(move _3) -> bb2; // scope 0 at $DIR/move_projection.rs:+9:13: +9:44
+                                           // mir::Constant
+                                           // + span: $DIR/move_projection.rs:22:28: 22:34
+                                           // + literal: Const { ty: fn(u8) -> bool {opaque::<u8>}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          return;                          // scope 0 at $DIR/move_projection.rs:+12:13: +12:21
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/move_projection.rs b/tests/mir-opt/copy-prop/move_projection.rs
new file mode 100644 (file)
index 0000000..2a1bbae
--- /dev/null
@@ -0,0 +1,34 @@
+// unit-test: CopyProp
+
+#![feature(custom_mir, core_intrinsics)]
+#![allow(unused_assignments)]
+extern crate core;
+use core::intrinsics::mir::*;
+
+fn opaque(_: impl Sized) -> bool { true }
+
+struct Foo(u8);
+
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn f(a: Foo) -> bool {
+    mir!(
+        {
+            let b = a;
+            // This is a move out of a copy, so must become a copy of `a.0`.
+            let c = Move(b.0);
+            Call(RET, bb1, opaque(Move(a)))
+        }
+        bb1 = {
+            Call(RET, ret, opaque(Move(c)))
+        }
+        ret = {
+            Return()
+        }
+    )
+}
+
+fn main() {
+    assert!(f(Foo(0)));
+}
+
+// EMIT_MIR move_projection.f.CopyProp.diff
index fce18fae4362f17224dfcc0ed6213575176167c5..d049c79d78deff2502ead980cb2ae0f4e45de9e5 100644 (file)
@@ -23,9 +23,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/enum.rs:+1:9: +1:10
-          Deinit(_1);                      // scope 0 at $DIR/enum.rs:+1:13: +1:21
-          ((_1 as V1).0: i32) = const 0_i32; // scope 0 at $DIR/enum.rs:+1:13: +1:21
-          discriminant(_1) = 0;            // scope 0 at $DIR/enum.rs:+1:13: +1:21
+          _1 = E::V1(const 0_i32);         // scope 0 at $DIR/enum.rs:+1:13: +1:21
           StorageLive(_2);                 // scope 1 at $DIR/enum.rs:+2:9: +2:10
           _3 = discriminant(_1);           // scope 1 at $DIR/enum.rs:+2:19: +2:20
           switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 1 at $DIR/enum.rs:+2:13: +2:20
index f66b00a9a224bca8f66558e259633574588b52ec..8f045eedfb05801413d24cb49b8faf8a6fe2bfc4 100644 (file)
@@ -17,8 +17,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/repr_transparent.rs:+1:9: +1:10
-          Deinit(_1);                      // scope 0 at $DIR/repr_transparent.rs:+1:13: +1:19
-          (_1.0: i32) = const 0_i32;       // scope 0 at $DIR/repr_transparent.rs:+1:13: +1:19
+          _1 = I32(const 0_i32);           // scope 0 at $DIR/repr_transparent.rs:+1:13: +1:19
           StorageLive(_2);                 // scope 1 at $DIR/repr_transparent.rs:+2:9: +2:10
           StorageLive(_3);                 // scope 1 at $DIR/repr_transparent.rs:+2:17: +2:26
           StorageLive(_4);                 // scope 1 at $DIR/repr_transparent.rs:+2:17: +2:20
@@ -31,9 +30,8 @@
 +         _3 = const 0_i32;                // scope 1 at $DIR/repr_transparent.rs:+2:17: +2:26
           StorageDead(_5);                 // scope 1 at $DIR/repr_transparent.rs:+2:25: +2:26
           StorageDead(_4);                 // scope 1 at $DIR/repr_transparent.rs:+2:25: +2:26
-          Deinit(_2);                      // scope 1 at $DIR/repr_transparent.rs:+2:13: +2:27
--         (_2.0: i32) = move _3;           // scope 1 at $DIR/repr_transparent.rs:+2:13: +2:27
-+         (_2.0: i32) = const 0_i32;       // scope 1 at $DIR/repr_transparent.rs:+2:13: +2:27
+-         _2 = I32(move _3);               // scope 1 at $DIR/repr_transparent.rs:+2:13: +2:27
++         _2 = I32(const 0_i32);           // scope 1 at $DIR/repr_transparent.rs:+2:13: +2:27
           StorageDead(_3);                 // scope 1 at $DIR/repr_transparent.rs:+2:26: +2:27
           _0 = const ();                   // scope 0 at $DIR/repr_transparent.rs:+0:11: +3:2
           StorageDead(_2);                 // scope 1 at $DIR/repr_transparent.rs:+3:1: +3:2
index 8126d4b8585e6573e8b9e8d684a1e99cfa4406a9..a91a755830d1507b651cd3ecd26ea9dde64df7f7 100644 (file)
@@ -23,9 +23,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/sibling_ptr.rs:+1:9: +1:14
-          Deinit(_1);                      // scope 0 at $DIR/sibling_ptr.rs:+1:27: +1:33
-          (_1.0: u8) = const 0_u8;         // scope 0 at $DIR/sibling_ptr.rs:+1:27: +1:33
-          (_1.1: u8) = const 0_u8;         // scope 0 at $DIR/sibling_ptr.rs:+1:27: +1:33
+          _1 = (const 0_u8, const 0_u8);   // scope 0 at $DIR/sibling_ptr.rs:+1:27: +1:33
           StorageLive(_2);                 // scope 1 at $DIR/sibling_ptr.rs:+2:5: +5:6
           StorageLive(_3);                 // scope 2 at $DIR/sibling_ptr.rs:+3:13: +3:14
           _3 = &raw mut (_1.0: u8);        // scope 2 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
index cfb2706c167cdeea9d9fe67d646e91c75eaf2160..53c62c0817391d51705e060ad9b1b1c811eebb6e 100644 (file)
@@ -21,8 +21,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/struct.rs:+1:9: +1:14
-          Deinit(_1);                      // scope 0 at $DIR/struct.rs:+1:17: +1:21
-          (_1.0: i32) = const 1_i32;       // scope 0 at $DIR/struct.rs:+1:17: +1:21
+          _1 = S(const 1_i32);             // scope 0 at $DIR/struct.rs:+1:17: +1:21
           StorageLive(_2);                 // scope 1 at $DIR/struct.rs:+2:9: +2:10
           StorageLive(_3);                 // scope 1 at $DIR/struct.rs:+2:13: +2:16
 -         _3 = (_1.0: i32);                // scope 1 at $DIR/struct.rs:+2:13: +2:16
index e028def00a116da1c3ab5b6be5830555bb299ee7..8ce4ce4ba976d1e42ffd78480ad38793037520e5 100644 (file)
@@ -25,9 +25,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/tuple.rs:+1:9: +1:14
-          Deinit(_1);                      // scope 0 at $DIR/tuple.rs:+1:17: +1:23
-          (_1.0: i32) = const 1_i32;       // scope 0 at $DIR/tuple.rs:+1:17: +1:23
-          (_1.1: i32) = const 2_i32;       // scope 0 at $DIR/tuple.rs:+1:17: +1:23
+          _1 = (const 1_i32, const 2_i32); // scope 0 at $DIR/tuple.rs:+1:17: +1:23
           StorageLive(_2);                 // scope 1 at $DIR/tuple.rs:+2:9: +2:10
           StorageLive(_3);                 // scope 1 at $DIR/tuple.rs:+2:13: +2:22
           StorageLive(_4);                 // scope 1 at $DIR/tuple.rs:+2:13: +2:16
@@ -43,9 +41,7 @@
 -         _2 = Add(move _3, const 3_i32);  // scope 1 at $DIR/tuple.rs:+2:13: +2:26
 +         _2 = const 6_i32;                // scope 1 at $DIR/tuple.rs:+2:13: +2:26
           StorageDead(_3);                 // scope 1 at $DIR/tuple.rs:+2:25: +2:26
-          Deinit(_1);                      // scope 2 at $DIR/tuple.rs:+3:5: +3:15
-          (_1.0: i32) = const 2_i32;       // scope 2 at $DIR/tuple.rs:+3:5: +3:15
-          (_1.1: i32) = const 3_i32;       // scope 2 at $DIR/tuple.rs:+3:5: +3:15
+          _1 = (const 2_i32, const 3_i32); // scope 2 at $DIR/tuple.rs:+3:5: +3:15
           StorageLive(_6);                 // scope 2 at $DIR/tuple.rs:+4:9: +4:10
           StorageLive(_7);                 // scope 2 at $DIR/tuple.rs:+4:13: +4:22
           StorageLive(_8);                 // scope 2 at $DIR/tuple.rs:+4:13: +4:16
diff --git a/tests/mir-opt/deaggregator_test.bar.Deaggregator.diff b/tests/mir-opt/deaggregator_test.bar.Deaggregator.diff
deleted file mode 100644 (file)
index db13648..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-- // MIR for `bar` before Deaggregator
-+ // MIR for `bar` after Deaggregator
-  
-  fn bar(_1: usize) -> Baz {
-      debug a => _1;                       // in scope 0 at $DIR/deaggregator_test.rs:+0:8: +0:9
-      let mut _0: Baz;                     // return place in scope 0 at $DIR/deaggregator_test.rs:+0:21: +0:24
-      let mut _2: usize;                   // in scope 0 at $DIR/deaggregator_test.rs:+1:14: +1:15
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/deaggregator_test.rs:+1:14: +1:15
-          _2 = _1;                         // scope 0 at $DIR/deaggregator_test.rs:+1:14: +1:15
--         _0 = Baz { x: move _2, y: const 0f32, z: const false }; // scope 0 at $DIR/deaggregator_test.rs:+1:5: +1:35
-+         Deinit(_0);                      // scope 0 at $DIR/deaggregator_test.rs:+1:5: +1:35
-+         (_0.0: usize) = move _2;         // scope 0 at $DIR/deaggregator_test.rs:+1:5: +1:35
-+         (_0.1: f32) = const 0f32;        // scope 0 at $DIR/deaggregator_test.rs:+1:5: +1:35
-+         (_0.2: bool) = const false;      // scope 0 at $DIR/deaggregator_test.rs:+1:5: +1:35
-          StorageDead(_2);                 // scope 0 at $DIR/deaggregator_test.rs:+1:34: +1:35
-          return;                          // scope 0 at $DIR/deaggregator_test.rs:+2:2: +2:2
-      }
-  }
-  
diff --git a/tests/mir-opt/deaggregator_test.rs b/tests/mir-opt/deaggregator_test.rs
deleted file mode 100644 (file)
index ee59402..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// unit-test: Deaggregator
-
-struct Baz {
-    x: usize,
-    y: f32,
-    z: bool,
-}
-
-// EMIT_MIR deaggregator_test.bar.Deaggregator.diff
-fn bar(a: usize) -> Baz {
-    Baz { x: a, y: 0.0, z: false }
-}
-
-fn main() {
-    // Make sure the function actually gets instantiated.
-    bar(0);
-}
diff --git a/tests/mir-opt/deaggregator_test_enum.bar.Deaggregator.diff b/tests/mir-opt/deaggregator_test_enum.bar.Deaggregator.diff
deleted file mode 100644 (file)
index f28c2b4..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-- // MIR for `bar` before Deaggregator
-+ // MIR for `bar` after Deaggregator
-  
-  fn bar(_1: usize) -> Baz {
-      debug a => _1;                       // in scope 0 at $DIR/deaggregator_test_enum.rs:+0:8: +0:9
-      let mut _0: Baz;                     // return place in scope 0 at $DIR/deaggregator_test_enum.rs:+0:21: +0:24
-      let mut _2: usize;                   // in scope 0 at $DIR/deaggregator_test_enum.rs:+1:19: +1:20
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/deaggregator_test_enum.rs:+1:19: +1:20
-          _2 = _1;                         // scope 0 at $DIR/deaggregator_test_enum.rs:+1:19: +1:20
--         _0 = Baz::Foo { x: move _2 };    // scope 0 at $DIR/deaggregator_test_enum.rs:+1:5: +1:22
-+         Deinit(_0);                      // scope 0 at $DIR/deaggregator_test_enum.rs:+1:5: +1:22
-+         ((_0 as Foo).0: usize) = move _2; // scope 0 at $DIR/deaggregator_test_enum.rs:+1:5: +1:22
-+         discriminant(_0) = 1;            // scope 0 at $DIR/deaggregator_test_enum.rs:+1:5: +1:22
-          StorageDead(_2);                 // scope 0 at $DIR/deaggregator_test_enum.rs:+1:21: +1:22
-          return;                          // scope 0 at $DIR/deaggregator_test_enum.rs:+2:2: +2:2
-      }
-  }
-  
diff --git a/tests/mir-opt/deaggregator_test_enum.rs b/tests/mir-opt/deaggregator_test_enum.rs
deleted file mode 100644 (file)
index ea402da..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// unit-test: Deaggregator
-
-enum Baz {
-    Empty,
-    Foo { x: usize },
-}
-
-// EMIT_MIR deaggregator_test_enum.bar.Deaggregator.diff
-fn bar(a: usize) -> Baz {
-    Baz::Foo { x: a }
-}
-
-fn main() {
-    let x = bar(10);
-    match x {
-        Baz::Empty => println!("empty"),
-        Baz::Foo { x } => println!("{}", x),
-    };
-}
diff --git a/tests/mir-opt/deaggregator_test_enum_2.rs b/tests/mir-opt/deaggregator_test_enum_2.rs
deleted file mode 100644 (file)
index 955c317..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// unit-test: Deaggregator
-// Test that deaggregate fires in more than one basic block
-
-enum Foo {
-    A(i32),
-    B(i32),
-}
-
-// EMIT_MIR deaggregator_test_enum_2.test1.Deaggregator.diff
-fn test1(x: bool, y: i32) -> Foo {
-    if x {
-        Foo::A(y)
-    } else {
-        Foo::B(y)
-    }
-}
-
-fn main() {
-    // Make sure the function actually gets instantiated.
-    test1(false, 0);
-}
diff --git a/tests/mir-opt/deaggregator_test_enum_2.test1.Deaggregator.diff b/tests/mir-opt/deaggregator_test_enum_2.test1.Deaggregator.diff
deleted file mode 100644 (file)
index 210d384..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-- // MIR for `test1` before Deaggregator
-+ // MIR for `test1` after Deaggregator
-  
-  fn test1(_1: bool, _2: i32) -> Foo {
-      debug x => _1;                       // in scope 0 at $DIR/deaggregator_test_enum_2.rs:+0:10: +0:11
-      debug y => _2;                       // in scope 0 at $DIR/deaggregator_test_enum_2.rs:+0:19: +0:20
-      let mut _0: Foo;                     // return place in scope 0 at $DIR/deaggregator_test_enum_2.rs:+0:30: +0:33
-      let mut _3: bool;                    // in scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:8: +1:9
-      let mut _4: i32;                     // in scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:16: +2:17
-      let mut _5: i32;                     // in scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:16: +4:17
-  
-      bb0: {
-          StorageLive(_3);                 // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:8: +1:9
-          _3 = _1;                         // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:8: +1:9
-          switchInt(move _3) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:8: +1:9
-      }
-  
-      bb1: {
-          StorageLive(_4);                 // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:16: +2:17
-          _4 = _2;                         // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:16: +2:17
--         _0 = Foo::A(move _4);            // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:9: +2:18
-+         Deinit(_0);                      // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:9: +2:18
-+         ((_0 as A).0: i32) = move _4;    // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:9: +2:18
-+         discriminant(_0) = 0;            // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:9: +2:18
-          StorageDead(_4);                 // scope 0 at $DIR/deaggregator_test_enum_2.rs:+2:17: +2:18
-          goto -> bb3;                     // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:5: +5:6
-      }
-  
-      bb2: {
-          StorageLive(_5);                 // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:16: +4:17
-          _5 = _2;                         // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:16: +4:17
--         _0 = Foo::B(move _5);            // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:9: +4:18
-+         Deinit(_0);                      // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:9: +4:18
-+         ((_0 as B).0: i32) = move _5;    // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:9: +4:18
-+         discriminant(_0) = 1;            // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:9: +4:18
-          StorageDead(_5);                 // scope 0 at $DIR/deaggregator_test_enum_2.rs:+4:17: +4:18
-          goto -> bb3;                     // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:5: +5:6
-      }
-  
-      bb3: {
-          StorageDead(_3);                 // scope 0 at $DIR/deaggregator_test_enum_2.rs:+5:5: +5:6
-          return;                          // scope 0 at $DIR/deaggregator_test_enum_2.rs:+6:2: +6:2
-      }
-  }
-  
diff --git a/tests/mir-opt/deaggregator_test_multiple.rs b/tests/mir-opt/deaggregator_test_multiple.rs
deleted file mode 100644 (file)
index 46305fe..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// unit-test: Deaggregator
-// Test that deaggregate fires more than once per block
-
-enum Foo {
-    A(i32),
-    B,
-}
-
-// EMIT_MIR deaggregator_test_multiple.test.Deaggregator.diff
-fn test(x: i32) -> [Foo; 2] {
-    [Foo::A(x), Foo::A(x)]
-}
-
-fn main() {
-    // Make sure the function actually gets instantiated.
-    test(0);
-}
diff --git a/tests/mir-opt/deaggregator_test_multiple.test.Deaggregator.diff b/tests/mir-opt/deaggregator_test_multiple.test.Deaggregator.diff
deleted file mode 100644 (file)
index cf5da27..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-- // MIR for `test` before Deaggregator
-+ // MIR for `test` after Deaggregator
-  
-  fn test(_1: i32) -> [Foo; 2] {
-      debug x => _1;                       // in scope 0 at $DIR/deaggregator_test_multiple.rs:+0:9: +0:10
-      let mut _0: [Foo; 2];                // return place in scope 0 at $DIR/deaggregator_test_multiple.rs:+0:20: +0:28
-      let mut _2: Foo;                     // in scope 0 at $DIR/deaggregator_test_multiple.rs:+1:6: +1:15
-      let mut _3: i32;                     // in scope 0 at $DIR/deaggregator_test_multiple.rs:+1:13: +1:14
-      let mut _4: Foo;                     // in scope 0 at $DIR/deaggregator_test_multiple.rs:+1:17: +1:26
-      let mut _5: i32;                     // in scope 0 at $DIR/deaggregator_test_multiple.rs:+1:24: +1:25
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:6: +1:15
-          StorageLive(_3);                 // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:13: +1:14
-          _3 = _1;                         // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:13: +1:14
--         _2 = Foo::A(move _3);            // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:6: +1:15
-+         Deinit(_2);                      // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:6: +1:15
-+         ((_2 as A).0: i32) = move _3;    // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:6: +1:15
-+         discriminant(_2) = 0;            // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:6: +1:15
-          StorageDead(_3);                 // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:14: +1:15
-          StorageLive(_4);                 // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:17: +1:26
-          StorageLive(_5);                 // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:24: +1:25
-          _5 = _1;                         // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:24: +1:25
--         _4 = Foo::A(move _5);            // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:17: +1:26
-+         Deinit(_4);                      // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:17: +1:26
-+         ((_4 as A).0: i32) = move _5;    // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:17: +1:26
-+         discriminant(_4) = 0;            // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:17: +1:26
-          StorageDead(_5);                 // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:25: +1:26
-          _0 = [move _2, move _4];         // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:5: +1:27
-          StorageDead(_4);                 // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:26: +1:27
-          StorageDead(_2);                 // scope 0 at $DIR/deaggregator_test_multiple.rs:+1:26: +1:27
-          return;                          // scope 0 at $DIR/deaggregator_test_multiple.rs:+2:2: +2:2
-      }
-  }
-  
index 98a02ee38dd1769b2e6bd0cf5bcac0f74b14b2eb..5383d1be129823618bb50b694a8d9bda6e56d624 100644 (file)
@@ -25,9 +25,7 @@
           _4 = _1;                         // scope 0 at $DIR/early_otherwise_branch.rs:+1:12: +1:13
           StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16
           _5 = _2;                         // scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16
-          Deinit(_3);                      // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
-          (_3.0: std::option::Option<u32>) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
-          (_3.1: std::option::Option<u32>) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
+          _3 = (move _4, move _5);         // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17
           _7 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
index aa75c44b809a90543004dbd7f49c9ec9d949953c..b3e21ff49bdf3a0a652e73d7c20d9d892f20ffeb 100644 (file)
@@ -26,9 +26,7 @@
           _4 = _1;                         // scope 0 at $DIR/early_otherwise_branch.rs:+1:12: +1:13
           StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16
           _5 = _2;                         // scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16
-          Deinit(_3);                      // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
-          (_3.0: std::option::Option<u32>) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
-          (_3.1: std::option::Option<u32>) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
+          _3 = (move _4, move _5);         // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17
           _8 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
index cea6ff7cd05e07bd02d4a2c46194cb30969f9908..e098a88eb5578555b8642cc43d6b1e40f1c12098 100644 (file)
@@ -25,9 +25,7 @@
           _4 = _1;                         // scope 0 at $DIR/early_otherwise_branch.rs:+1:12: +1:13
           StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16
           _5 = _2;                         // scope 0 at $DIR/early_otherwise_branch.rs:+1:15: +1:16
-          Deinit(_3);                      // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
-          (_3.0: std::option::Option<u32>) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
-          (_3.1: std::option::Option<bool>) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
+          _3 = (move _4, move _5);         // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17
           _7 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
index b90d70ce43aa0ca0d884663a1a775d85a3a3edf6..ec3b4bbdff42f394790b6befc07f15161066ca4a 100644 (file)
           _6 = _2;                         // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:15: +1:16
           StorageLive(_7);                 // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:18: +1:19
           _7 = _3;                         // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:18: +1:19
-          Deinit(_4);                      // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20
-          (_4.0: std::option::Option<u32>) = move _5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20
-          (_4.1: std::option::Option<u32>) = move _6; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20
-          (_4.2: std::option::Option<u32>) = move _7; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20
+          _4 = (move _5, move _6, move _7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20
           StorageDead(_7);                 // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:19: +1:20
           StorageDead(_6);                 // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:19: +1:20
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:19: +1:20
index 9edd1a39f45f9b050f4a50d1d1c5875461e45ffe..a91d0d7cf730fc5959209fd654b15e91d6cacd51 100644 (file)
@@ -73,9 +73,7 @@
           _5 = _1;                         // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16
           StorageLive(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23
           _6 = _2;                         // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23
-          Deinit(_4);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
+          _4 = (move _5, move _6);         // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
           StorageDead(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24
           _34 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
   
       bb2: {
           StorageLive(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
-          Deinit(_33);                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
-          Deinit(_0);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
-          ((_0 as Err).0: ()) = move _33;  // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
-          discriminant(_0) = 1;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
+          _33 = ();                        // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
+          _0 = Result::<ViewportPercentageLength, ()>::Err(move _33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
           StorageDead(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:27: +10:28
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
           _14 = Add(move _15, move _16);   // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49
           StorageDead(_16);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49
           StorageDead(_15);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49
-          Deinit(_3);                      // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
-          ((_3 as Vw).0: f32) = move _14;  // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
-          discriminant(_3) = 0;            // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
+          _3 = ViewportPercentageLength::Vw(move _14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
           StorageDead(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
           StorageDead(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
           StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
           _19 = Add(move _20, move _21);   // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49
           StorageDead(_21);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49
           StorageDead(_20);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49
-          Deinit(_3);                      // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
-          ((_3 as Vh).0: f32) = move _19;  // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
-          discriminant(_3) = 1;            // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
+          _3 = ViewportPercentageLength::Vh(move _19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
           StorageDead(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
           StorageDead(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
           StorageDead(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
           _24 = Add(move _25, move _26);   // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55
           StorageDead(_26);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55
           StorageDead(_25);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55
-          Deinit(_3);                      // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
-          ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
-          discriminant(_3) = 2;            // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
+          _3 = ViewportPercentageLength::Vmin(move _24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
           StorageDead(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
           StorageDead(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
           StorageDead(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
           _29 = Add(move _30, move _31);   // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55
           StorageDead(_31);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55
           StorageDead(_30);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55
-          Deinit(_3);                      // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
-          ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
-          discriminant(_3) = 3;            // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
+          _3 = ViewportPercentageLength::Vmax(move _29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
           StorageDead(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
           StorageDead(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
           StorageDead(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
       }
   
       bb10: {
-          Deinit(_0);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
-          ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
-          discriminant(_0) = 0;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
+          _0 = Result::<ViewportPercentageLength, ()>::Ok(move _3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
           goto -> bb11;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
index 82d8b2fc5a463a740edb395c2c44968a2269f016..6468eb5f8dde590946844314f7fef99d55e4e188 100644 (file)
@@ -32,9 +32,7 @@
           _4 = _1;                         // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:12: +1:13
           StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:15: +1:16
           _5 = _2;                         // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:15: +1:16
-          Deinit(_3);                      // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17
-          (_3.0: std::option::Option<u32>) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17
-          (_3.1: std::option::Option<u32>) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17
+          _3 = (move _4, move _5);         // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:16: +1:17
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:16: +1:17
           _8 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17
index 7c5d28069d59d4f2bf1ec800f8fd4e1a7e179eb3..5ebaacd4ba91d71d7469fd621a8f56091d090dda 100644 (file)
       }
   
       bb2: {
-          Deinit(_6);                      // scope 1 at $DIR/funky_arms.rs:+10:17: +10:41
-          discriminant(_6) = 1;            // scope 1 at $DIR/funky_arms.rs:+10:17: +10:41
+-         _6 = MinusPlus;                  // scope 1 at $DIR/funky_arms.rs:+10:17: +10:41
++         _6 = const MinusPlus;            // scope 1 at $DIR/funky_arms.rs:+10:17: +10:41
++                                          // mir::Constant
++                                          // + span: $DIR/funky_arms.rs:21:17: 21:41
++                                          // + literal: Const { ty: Sign, val: Value(Scalar(0x01)) }
           goto -> bb4;                     // scope 1 at $DIR/funky_arms.rs:+10:17: +10:41
       }
   
       bb3: {
-          Deinit(_6);                      // scope 1 at $DIR/funky_arms.rs:+9:18: +9:38
-          discriminant(_6) = 0;            // scope 1 at $DIR/funky_arms.rs:+9:18: +9:38
+-         _6 = Minus;                      // scope 1 at $DIR/funky_arms.rs:+9:18: +9:38
++         _6 = const Minus;                // scope 1 at $DIR/funky_arms.rs:+9:18: +9:38
++                                          // mir::Constant
++                                          // + span: $DIR/funky_arms.rs:20:18: 20:38
++                                          // + literal: Const { ty: Sign, val: Value(Scalar(0x00)) }
           goto -> bb4;                     // scope 1 at $DIR/funky_arms.rs:+9:18: +9:38
       }
   
index 2f096c3e0a189e07c2b25dab943efc4f9e03b119..7efda05d2b88143ac8ceda6b8a0711c3cc4d6e10 100644 (file)
@@ -54,9 +54,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator_tiny.rs:19:16: 19:24
         StorageLive(_6);                 // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
         StorageLive(_7);                 // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
         _7 = ();                         // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
-        Deinit(_0);                      // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
-        ((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
-        discriminant(_0) = 0;            // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
+        _0 = GeneratorState::<(), ()>::Yielded(move _7); // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
         discriminant((*(_1.0: &mut [generator@$DIR/generator_tiny.rs:19:16: 19:24]))) = 3; // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
         return;                          // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
     }
index 75ea69a42eb595283c0e7de09384c5286c1068ac..501390c3bf1016066a95e879f238ceee402ec00a 100644 (file)
@@ -13,7 +13,7 @@
           StorageLive(_3);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:6
           _3 = &_1;                        // scope 0 at $DIR/cycle.rs:+1:5: +1:6
           StorageLive(_4);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:8
-          Deinit(_4);                      // scope 0 at $DIR/cycle.rs:+1:5: +1:8
+          _4 = ();                         // scope 0 at $DIR/cycle.rs:+1:5: +1:8
           _2 = <impl Fn() as Fn<()>>::call(move _3, move _4) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/cycle.rs:+1:5: +1:8
                                            // mir::Constant
                                            // + span: $DIR/cycle.rs:6:5: 6:6
index 9eb3a01eef91ad492de49d71ae712ff994579ec8..fff8d01712770dc85d2b52cffc49675421b55be0 100644 (file)
@@ -21,7 +21,15 @@ fn foo(_1: T, _2: i32) -> i32 {
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/inline_closure.rs:+1:9: +1:10
-        Deinit(_3);                      // scope 0 at $DIR/inline_closure.rs:+1:13: +1:24
+        _3 = [closure@foo::<T>::{closure#0}]; // scope 0 at $DIR/inline_closure.rs:+1:13: +1:24
+                                         // closure
+                                         // + def_id: DefId(0:6 ~ inline_closure[92ba]::foo::{closure#0})
+                                         // + substs: [
+                                         //     T,
+                                         //     i8,
+                                         //     extern "rust-call" fn((i32, i32)) -> i32,
+                                         //     (),
+                                         // ]
         StorageLive(_4);                 // scope 1 at $DIR/inline_closure.rs:+2:5: +2:6
         _4 = &_3;                        // scope 1 at $DIR/inline_closure.rs:+2:5: +2:6
         StorageLive(_5);                 // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
@@ -29,9 +37,7 @@ fn foo(_1: T, _2: i32) -> i32 {
         _6 = _2;                         // scope 1 at $DIR/inline_closure.rs:+2:7: +2:8
         StorageLive(_7);                 // scope 1 at $DIR/inline_closure.rs:+2:10: +2:11
         _7 = _2;                         // scope 1 at $DIR/inline_closure.rs:+2:10: +2:11
-        Deinit(_5);                      // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
-        (_5.0: i32) = move _6;           // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
-        (_5.1: i32) = move _7;           // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
+        _5 = (move _6, move _7);         // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
         StorageLive(_8);                 // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
         _8 = move (_5.0: i32);           // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
         StorageLive(_9);                 // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
index dd32eb2d8d1f7fcb68646b2a27cb1e6382f3bf51..dab2043064f39802d924604ba1874f3a4f4fd5ad 100644 (file)
@@ -24,7 +24,15 @@ fn foo(_1: T, _2: &i32) -> i32 {
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/inline_closure_borrows_arg.rs:+1:9: +1:10
-        Deinit(_3);                      // scope 0 at $DIR/inline_closure_borrows_arg.rs:+1:13: +4:6
+        _3 = [closure@foo::<T>::{closure#0}]; // scope 0 at $DIR/inline_closure_borrows_arg.rs:+1:13: +4:6
+                                         // closure
+                                         // + def_id: DefId(0:6 ~ inline_closure_borrows_arg[96e9]::foo::{closure#0})
+                                         // + substs: [
+                                         //     T,
+                                         //     i8,
+                                         //     for<'a, 'b> extern "rust-call" fn((&'a i32, &'b i32)) -> i32,
+                                         //     (),
+                                         // ]
         StorageLive(_4);                 // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:6
         _4 = &_3;                        // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:6
         StorageLive(_5);                 // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
@@ -32,9 +40,7 @@ fn foo(_1: T, _2: &i32) -> i32 {
         _6 = &(*_2);                     // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:7: +5:8
         StorageLive(_7);                 // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:10: +5:11
         _7 = &(*_2);                     // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:10: +5:11
-        Deinit(_5);                      // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
-        (_5.0: &i32) = move _6;          // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
-        (_5.1: &i32) = move _7;          // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
+        _5 = (move _6, move _7);         // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
         StorageLive(_8);                 // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
         _8 = move (_5.0: &i32);          // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
         StorageLive(_9);                 // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
index fd19c288666bd5379c29d1b42be0a7e6d7f970f9..84fd051e0a3518280555a38dbfa40c4581752187 100644 (file)
@@ -30,9 +30,15 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         _4 = &_2;                        // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
         StorageLive(_5);                 // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
         _5 = &_1;                        // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
-        Deinit(_3);                      // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
-        (_3.0: &i32) = move _4;          // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
-        (_3.1: &T) = move _5;            // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+        _3 = [closure@foo::<T>::{closure#0}] { q: move _4, t: move _5 }; // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+                                         // closure
+                                         // + def_id: DefId(0:6 ~ inline_closure_captures[8bc0]::foo::{closure#0})
+                                         // + substs: [
+                                         //     T,
+                                         //     i8,
+                                         //     extern "rust-call" fn((i32,)) -> (i32, T),
+                                         //     (&i32, &T),
+                                         // ]
         StorageDead(_5);                 // scope 0 at $DIR/inline_closure_captures.rs:+1:16: +1:17
         StorageDead(_4);                 // scope 0 at $DIR/inline_closure_captures.rs:+1:16: +1:17
         StorageLive(_6);                 // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:6
@@ -40,8 +46,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         StorageLive(_7);                 // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
         StorageLive(_8);                 // scope 1 at $DIR/inline_closure_captures.rs:+2:7: +2:8
         _8 = _2;                         // scope 1 at $DIR/inline_closure_captures.rs:+2:7: +2:8
-        Deinit(_7);                      // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
-        (_7.0: i32) = move _8;           // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
+        _7 = (move _8,);                 // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
         StorageLive(_9);                 // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
         _9 = move (_7.0: i32);           // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
         StorageLive(_10);                // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20
@@ -50,9 +55,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         StorageLive(_11);                // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
         _13 = deref_copy ((*_6).1: &T);  // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
         _11 = (*_13);                    // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
-        Deinit(_0);                      // scope 2 at $DIR/inline_closure_captures.rs:+1:18: +1:24
-        (_0.0: i32) = move _10;          // scope 2 at $DIR/inline_closure_captures.rs:+1:18: +1:24
-        (_0.1: T) = move _11;            // scope 2 at $DIR/inline_closure_captures.rs:+1:18: +1:24
+        _0 = (move _10, move _11);       // scope 2 at $DIR/inline_closure_captures.rs:+1:18: +1:24
         StorageDead(_11);                // scope 2 at $DIR/inline_closure_captures.rs:+1:23: +1:24
         StorageDead(_10);                // scope 2 at $DIR/inline_closure_captures.rs:+1:23: +1:24
         StorageDead(_9);                 // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
index f82fcf4c82129634ee7d4a2288e85226031378fe..e1b2f7dbf358d0117473f706aae225250a667f5e 100644 (file)
@@ -48,9 +48,7 @@
 +         StorageDead(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
 +         StorageLive(_8);                 // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
 +         _8 = move _3;                    // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
-+         Deinit(_1);                      // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
-+         (_1.0: !) = move _8;             // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
-+         (_1.1: !) = move _9;             // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
++         _1 = (move _8, move _9);         // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
 +         StorageDead(_8);                 // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11
 +         StorageDead(_3);                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +         drop(_2) -> bb2;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
index 57574acf92354e375130f3997eb20351aa41309d..95d649f89ba6b34d73095dda74cb4dc67dfd4cb4 100644 (file)
 -     }
 - 
 -     bb1: {
-+         Deinit(_4);                      // scope 2 at $DIR/inline_generator.rs:15:5: 15:41
-+         discriminant(_4) = 0;            // scope 2 at $DIR/inline_generator.rs:15:5: 15:41
++         _4 = [generator@$DIR/inline_generator.rs:15:5: 15:8 (#0)]; // scope 2 at $DIR/inline_generator.rs:15:5: 15:41
++                                          // generator
++                                          // + def_id: DefId(0:7 ~ inline_generator[ea31]::g::{closure#0})
++                                          // + substs: [
++                                          //     bool,
++                                          //     i32,
++                                          //     bool,
++                                          //     {bool, i32},
++                                          //     (),
++                                          // ]
++                                          // + movability: Movable
           _3 = &mut _4;                    // scope 0 at $DIR/inline_generator.rs:+1:23: +1:31
 -         _2 = Pin::<&mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline_generator.rs:+1:14: +1:32
 -                                          // mir::Constant
@@ -59,8 +68,7 @@
 +         _5 = move _3;                    // scope 4 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         StorageLive(_6);                 // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         _6 = move _5;                    // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
-+         Deinit(_2);                      // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
-+         (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]) = move _6; // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
++         _2 = Pin::<&mut [generator@$DIR/inline_generator.rs:15:5: 15:8]> { pointer: move _6 }; // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         StorageDead(_6);                 // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         StorageDead(_5);                 // scope 4 at $SRC_DIR/core/src/pin.rs:LL:COL
           StorageDead(_3);                 // scope 0 at $DIR/inline_generator.rs:+1:31: +1:32
 +     }
 + 
 +     bb6: {
-+         Deinit(_1);                      // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
-+         ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
-+         discriminant(_1) = 0;            // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
++         _1 = GeneratorState::<i32, bool>::Yielded(move _8); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
 +         _11 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
 +         discriminant((*_11)) = 3;        // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
 +         goto -> bb1;                     // scope 0 at $DIR/inline_generator.rs:15:11: 15:39
 +     bb7: {
 +         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) = _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
++         _1 = GeneratorState::<i32, bool>::Complete(_7); // 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
 +         goto -> bb1;                     // scope 0 at $DIR/inline_generator.rs:15:41: 15:41
index a28da146e378659e68193505aeba97c8cb3d0d08..a1cbf0d3e0ddea636215f47eb8220bece8d79c82 100644 (file)
@@ -51,9 +51,7 @@
 +                                          // + 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(_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
++         _9 = Vec::<u32> { buf: move _10, len: 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
index d99ae1a6c7c8356b0b15588063b453f55d54a9dd..4dd1aad489dd48e919b08e9e38715b5fe1a2f8bc 100644 (file)
@@ -20,14 +20,20 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:9: +1:10
-        Deinit(_1);                      // scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:13: +1:33
+        _1 = [closure@$DIR/issue_76997_inline_scopes_parenting.rs:5:13: 5:16]; // scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:13: +1:33
+                                         // closure
+                                         // + def_id: DefId(0:4 ~ issue_76997_inline_scopes_parenting[bc59]::main::{closure#0})
+                                         // + substs: [
+                                         //     i8,
+                                         //     extern "rust-call" fn(((),)),
+                                         //     (),
+                                         // ]
         StorageLive(_2);                 // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:6
         _2 = &_1;                        // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:6
         StorageLive(_3);                 // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
         StorageLive(_4);                 // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:7: +2:9
-        Deinit(_4);                      // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:7: +2:9
-        Deinit(_3);                      // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
-        (_3.0: ()) = move _4;            // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
+        _4 = ();                         // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:7: +2:9
+        _3 = (move _4,);                 // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
         StorageLive(_5);                 // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
         _5 = move (_3.0: ());            // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
         StorageLive(_6);                 // scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:23: +1:24
index 51a98465fd9a78316f0ea331c4b10f043fcdfd7d..aa62e4a165e197d811e4f90cd9fe027132fe9827 100644 (file)
@@ -25,7 +25,7 @@
       bb1: {
           _3 = &_4;                        // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
           StorageLive(_5);                 // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
-          Deinit(_5);                      // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
+          _5 = ();                         // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
 -         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
 -                                          // mir::Constant
 -                                          // + span: $DIR/issue_78442.rs:11:5: 11:15
index e47466c5e80476a5b9915b747bc8c4a9b7b907b8..21055c6bfb57f4e3eb21546d374d8ca122528cad 100644 (file)
@@ -24,7 +24,7 @@
       bb1: {
           _3 = &_4;                        // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
           StorageLive(_5);                 // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
-          Deinit(_5);                      // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
+          _5 = ();                         // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
 -         _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
 +         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
                                            // mir::Constant
index 93804780371cd41d11207b768bdad81a67f63269..bcda1288045664ae98db4fb45b0a140b6767788e 100644 (file)
   
       bb7: {
           StorageDead(_6);                 // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36
-          Deinit(_0);                      // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
-          ((_0 as Some).0: [u8; 4]) = move _5; // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
-          discriminant(_0) = 1;            // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
+          _0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
           StorageDead(_5);                 // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39
           StorageDead(_4);                 // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6
           goto -> bb9;                     // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
       }
   
       bb8: {
-          Deinit(_0);                      // scope 1 at $DIR/issue_75439.rs:+7:9: +7:13
-          discriminant(_0) = 0;            // scope 1 at $DIR/issue_75439.rs:+7:9: +7:13
+          _0 = Option::<[u8; 4]>::None;    // scope 1 at $DIR/issue_75439.rs:+7:9: +7:13
           goto -> bb9;                     // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
       }
   
index ec15fd1ef74d60f4ad11fb9f5ffb2aa2193a1f04..5c972a00e464d846ba03d11487e6cc69639fc3e4 100644 (file)
@@ -25,9 +25,9 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:12
-          Deinit(_1);                      // scope 0 at $DIR/lower_intrinsics.rs:+1:15: +1:17
+          _1 = ();                         // scope 0 at $DIR/lower_intrinsics.rs:+1:15: +1:17
           StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:16
-          Deinit(_2);                      // scope 1 at $DIR/lower_intrinsics.rs:+2:19: +2:21
+          _2 = ();                         // scope 1 at $DIR/lower_intrinsics.rs:+2:19: +2:21
           StorageLive(_3);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
           StorageLive(_4);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:59
           StorageLive(_5);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45
index be91b0bfe6820f1ea61ef4ee00ab1d9ca4109a06..92f8d4e14abbde628f7c54d700f7078b952b6466 100644 (file)
@@ -41,7 +41,7 @@
 -         _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22
 -         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22
 -         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21
--         Deinit(_6);                      // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
+-         _6 = ();                         // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
 -         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
 -     }
 - 
@@ -54,7 +54,7 @@
 +         _3 = Eq(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
           _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22
           _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21
-          Deinit(_6);                      // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
+          _6 = ();                         // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
 -         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
 -     }
 - 
           _9 = _4;                         // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
           StorageLive(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
           _10 = _5;                        // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
-          Deinit(_0);                      // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.0: bool) = move _7;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.1: bool) = move _8;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.2: bool) = move _9;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.3: bool) = move _10;         // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
+          _0 = (move _7, move _8, move _9, move _10); // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
           StorageDead(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
           StorageDead(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
           StorageDead(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
index aa8092ece663a7e53b8cd3efa017ffc6cf763c8e..0580f73341d21fdf5ae84496bd47e143db3ce163 100644 (file)
@@ -34,7 +34,7 @@
 -     }
 - 
 -     bb4: {
-          Deinit(_0);                      // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11
+          _0 = ();                         // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11
 -         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
 +         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
       }
index 193104dd30e7e3e711c46390732435ce5cfd704e..20e8ef2f72029daf9e512f55e3e7601080cca4dd 100644 (file)
@@ -20,7 +20,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
           StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
-          Deinit(_2);                      // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
+          _2 = ();                         // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
           StorageLive(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
           StorageLive(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
           StorageLive(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
index e522534867d50c4747798c0b8f143ad7f02886cb..210f178a0a9e5d32e7068dd5c6cd933c7a28a128 100644 (file)
@@ -16,20 +16,15 @@ fn main() -> () {
         StorageLive(_1);                 // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:9: +1:14
         StorageLive(_2);                 // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:24: +1:42
         StorageLive(_3);                 // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:32: +1:41
-        Deinit(_3);                      // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:32: +1:41
-        (_3.0: usize) = const 0_usize;   // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:32: +1:41
-        Deinit(_2);                      // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:24: +1:42
-        (_2.0: Droppy) = move _3;        // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:24: +1:42
+        _3 = Droppy(const 0_usize);      // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:32: +1:41
+        _2 = Aligned(move _3);           // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:24: +1:42
         StorageDead(_3);                 // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:41: +1:42
-        Deinit(_1);                      // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:17: +1:43
-        (_1.0: Aligned) = move _2;       // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:17: +1:43
+        _1 = Packed(move _2);            // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:17: +1:43
         StorageDead(_2);                 // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:42: +1:43
         StorageLive(_4);                 // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:11: +2:29
         StorageLive(_5);                 // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:19: +2:28
-        Deinit(_5);                      // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:19: +2:28
-        (_5.0: usize) = const 0_usize;   // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:19: +2:28
-        Deinit(_4);                      // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:11: +2:29
-        (_4.0: Droppy) = move _5;        // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:11: +2:29
+        _5 = Droppy(const 0_usize);      // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:19: +2:28
+        _4 = Aligned(move _5);           // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:11: +2:29
         StorageDead(_5);                 // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:28: +2:29
         StorageLive(_6);                 // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
         _6 = move (_1.0: Aligned);       // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
index ed1d0b87f603373ada39bd462539ebbf2207f29a..a8dd91efc379f86fef4c776c80d2a693f00d806a 100644 (file)
@@ -31,9 +31,7 @@
           _1 = const 0_i32;                // scope 0 at $DIR/remove_storage_markers.rs:+1:19: +1:20
 -         StorageLive(_2);                 // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
 -         StorageLive(_3);                 // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
-          Deinit(_3);                      // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
-          (_3.0: i32) = const 0_i32;       // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
-          (_3.1: i32) = const 10_i32;      // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+          _3 = std::ops::Range::<i32> { start: const 0_i32, end: const 10_i32 }; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           _2 = <std::ops::Range<i32> as IntoIterator>::into_iter(move _3) -> bb1; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
                                            // mir::Constant
                                            // + span: $DIR/remove_storage_markers.rs:10:14: 10:19
index 12e914e25e0c83b2ef61c2c0440f0ab1796f5d49..af34bc5edb7fe640fcde983caf154d8ce5a21ef1 100644 (file)
@@ -2,9 +2,12 @@
 
 fn get_union() -> Foo {
     let mut _0: Foo;                     // return place in scope 0 at $DIR/remove_zsts.rs:+0:19: +0:22
+    let mut _1: ();                      // in scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
 
     bb0: {
-        Deinit(_0);                      // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
+        StorageLive(_1);                 // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
+        _0 = Foo { x: move _1 };         // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
+        StorageDead(_1);                 // scope 0 at $DIR/remove_zsts.rs:+1:17: +1:18
         return;                          // scope 0 at $DIR/remove_zsts.rs:+2:2: +2:2
     }
 }
index 169b7b1054b474a588ad675e8bbbff6bc818d2cc..0af29b2babc2b114aa841f6432c9b2a616c99754 100644 (file)
@@ -7,11 +7,9 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
--         Deinit(_1);                      // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
+-         _1 = ();                         // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
 +         nop;                             // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
-          Deinit(_0);                      // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
--         (_0.0: ()) = move _1;            // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
-+         nop;                             // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
+          _0 = Foo { x: move _1 };         // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
           StorageDead(_1);                 // scope 0 at $DIR/remove_zsts.rs:+1:17: +1:18
           return;                          // scope 0 at $DIR/remove_zsts.rs:+2:2: +2:2
       }
index 19b726e74845392e72cec5427d02ef1543fd047d..3b479710b4f2d3af3f6b2f42deb80dfdddcd0811 100644 (file)
@@ -122,9 +122,7 @@ fn array_casts() -> () {
                                          // + literal: Const { ty: &usize, val: Unevaluated(array_casts, [], Some(promoted[0])) }
         Retag(_35);                      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _18 = &(*_35);                   // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        Deinit(_13);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        (_13.0: &usize) = move _14;      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        (_13.1: &usize) = move _18;      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _13 = (move _14, move _18);      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         Retag(_13);                      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageDead(_18);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageDead(_14);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -150,8 +148,7 @@ fn array_casts() -> () {
 
     bb3: {
         StorageLive(_27);                // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        Deinit(_27);                     // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        discriminant(_27) = 0;           // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _27 = core::panicking::AssertKind::Eq; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageLive(_28);                // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageLive(_29);                // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _29 = move _27;                  // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -164,8 +161,7 @@ fn array_casts() -> () {
         _33 = &(*_21);                   // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _32 = &(*_33);                   // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageLive(_34);                // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        Deinit(_34);                     // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        discriminant(_34) = 0;           // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _34 = Option::<Arguments<'_>>::None; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         Retag(_34);                      // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _28 = core::panicking::assert_failed::<usize, usize>(move _29, move _30, move _32, move _34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                          // mir::Constant
index b853e450541729d82ad1b577e63cd67309746209..d7b6d64b6b7b7abb655d0cb729df2f36a4c19445 100644 (file)
@@ -62,8 +62,7 @@ fn main() -> () {
         StorageLive(_3);                 // scope 1 at $DIR/retag.rs:+3:13: +3:14
         StorageLive(_4);                 // scope 1 at $DIR/retag.rs:+3:17: +3:36
         StorageLive(_5);                 // scope 1 at $DIR/retag.rs:+3:17: +3:24
-        Deinit(_5);                      // scope 1 at $DIR/retag.rs:+3:17: +3:24
-        (_5.0: i32) = const 0_i32;       // scope 1 at $DIR/retag.rs:+3:17: +3:24
+        _5 = Test(const 0_i32);          // scope 1 at $DIR/retag.rs:+3:17: +3:24
         _4 = &_5;                        // scope 1 at $DIR/retag.rs:+3:17: +3:36
         StorageLive(_6);                 // scope 1 at $DIR/retag.rs:+3:29: +3:35
         StorageLive(_7);                 // scope 1 at $DIR/retag.rs:+3:29: +3:35
@@ -107,7 +106,14 @@ fn main() -> () {
         StorageDead(_2);                 // scope 1 at $DIR/retag.rs:+8:5: +8:6
         StorageLive(_13);                // scope 1 at $DIR/retag.rs:+11:9: +11:10
         StorageLive(_14);                // scope 1 at $DIR/retag.rs:+11:31: +14:6
-        Deinit(_14);                     // scope 1 at $DIR/retag.rs:+11:31: +14:6
+        _14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:+11:31: +14:6
+                                         // closure
+                                         // + def_id: DefId(0:14 ~ retag[4622]::main::{closure#0})
+                                         // + substs: [
+                                         //     i8,
+                                         //     for<'a> extern "rust-call" fn((&'a i32,)) -> &'a i32,
+                                         //     (),
+                                         // ]
         Retag(_14);                      // scope 1 at $DIR/retag.rs:+11:31: +14:6
         _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (Pointer(ClosureFnPointer(Normal))); // scope 1 at $DIR/retag.rs:+11:31: +14:6
         StorageDead(_14);                // scope 1 at $DIR/retag.rs:+11:47: +11:48
@@ -129,8 +135,7 @@ fn main() -> () {
         StorageLive(_19);                // scope 7 at $DIR/retag.rs:+18:5: +18:24
         StorageLive(_20);                // scope 7 at $DIR/retag.rs:+18:5: +18:24
         StorageLive(_21);                // scope 7 at $DIR/retag.rs:+18:5: +18:12
-        Deinit(_21);                     // scope 7 at $DIR/retag.rs:+18:5: +18:12
-        (_21.0: i32) = const 0_i32;      // scope 7 at $DIR/retag.rs:+18:5: +18:12
+        _21 = Test(const 0_i32);         // scope 7 at $DIR/retag.rs:+18:5: +18:12
         _20 = &_21;                      // scope 7 at $DIR/retag.rs:+18:5: +18:24
         StorageLive(_22);                // scope 7 at $DIR/retag.rs:+18:21: +18:23
         StorageLive(_23);                // scope 7 at $DIR/retag.rs:+18:21: +18:23
index e57544e09e2a0f6a137240c628ad852ebeff31a3..cb89d6340760f9ebc022d6b0f2ca9ad654d501e2 100644 (file)
           StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
           _4 = _1;                         // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
           _10 = discriminant(_4);          // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
--         switchInt(move _10) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-+         switchInt(move _10) -> [0: bb6, 1: bb4, otherwise: bb5]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+          switchInt(move _10) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
       }
   
       bb1: {
--         StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
--         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
--         switchInt(move _5) -> [0: bb2, 1: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
--     }
-- 
--     bb2: {
+          StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
+          _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
+          switchInt(move _5) -> [0: bb2, 1: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
+      }
+  
+      bb2: {
           StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
           _9 = ((_3 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
           _2 = _9;                         // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10
           StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          Deinit(_0);                      // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-          ((_0 as Ok).0: i32) = move _2;   // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-          discriminant(_0) = 0;            // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
+          _0 = Result::<i32, i32>::Ok(move _2); // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
           StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
           StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
       }
   
--     bb3: {
-+     bb2: {
+      bb3: {
           unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
       }
   
--     bb4: {
-+     bb3: {
+      bb4: {
           StorageLive(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
           _6 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
           StorageLive(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
@@ -97,9 +92,7 @@
           _18 = move _16;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           _17 = move _18;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
           StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          _0 = Result::<i32, i32>::Err(move _17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
           return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
       }
   
--     bb5: {
-+     bb4: {
+      bb5: {
           StorageLive(_13);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
           _13 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageLive(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageLive(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           _15 = move _13;                  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_14);                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_14 as Err).0: i32) = move _15; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_14) = 1;           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+          _14 = Result::<Infallible, i32>::Err(move _15); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_3);                      // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _14; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_3) = 1;            // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+          _3 = ControlFlow::<Result<Infallible, i32>, i32>::Break(move _14); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_13);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
--         goto -> bb1;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-+         StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-+         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         switchInt(move _5) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
+          goto -> bb1;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
       }
   
--     bb6: {
-+     bb5: {
+      bb6: {
           unreachable;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
       }
   
--     bb7: {
-+     bb6: {
+      bb7: {
           StorageLive(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
           _11 = move ((_4 as Ok).0: i32);  // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageLive(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
           _12 = move _11;                  // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_3);                      // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_3 as Continue).0: i32) = move _12; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_3) = 0;            // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
+          _3 = ControlFlow::<Result<Infallible, i32>, i32>::Continue(move _12); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
--         goto -> bb1;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-+         StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-+         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         switchInt(move _5) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
+          goto -> bb1;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
       }
   }
   
index 8cc0c6a18353c2b8ea33f0c5c25d065a6b1a0ff2..3c7e9dc6131523601efb5e967f447dec60005f5e 100644 (file)
           _6 = ((_1 as Err).0: usize);     // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
           StorageLive(_7);                 // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43
           _7 = _6;                         // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43
-          Deinit(_2);                      // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
-          ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
-          discriminant(_2) = 1;            // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
+          _2 = ControlFlow::<usize, i32>::Break(move _7); // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
           StorageDead(_7);                 // scope 2 at $DIR/separate_const_switch.rs:+8:43: +8:44
           StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
--         goto -> bb4;                     // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
-+         _8 = discriminant(_2);           // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-+         switchInt(move _8) -> [0: bb6, 1: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
+          goto -> bb4;                     // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
       }
   
       bb2: {
           _4 = ((_1 as Ok).0: i32);        // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
           StorageLive(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
           _5 = _4;                         // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
-          Deinit(_2);                      // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-          ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-          discriminant(_2) = 0;            // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
+          _2 = ControlFlow::<usize, i32>::Continue(move _5); // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
           StorageDead(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46
           StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46
--         goto -> bb4;                     // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46
--     }
-- 
--     bb4: {
+          goto -> bb4;                     // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46
+      }
+  
+      bb4: {
           _8 = discriminant(_2);           // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
--         switchInt(move _8) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-+         switchInt(move _8) -> [0: bb6, 1: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
+          switchInt(move _8) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
       }
   
--     bb5: {
-+     bb4: {
+      bb5: {
           StorageLive(_11);                // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
           _11 = ((_2 as Break).0: usize);  // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-          Deinit(_0);                      // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
-          discriminant(_0) = 0;            // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
+          _0 = Option::<i32>::None;        // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
           StorageDead(_11);                // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
--         goto -> bb8;                     // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
-+         goto -> bb7;                     // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
+          goto -> bb8;                     // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
       }
   
--     bb6: {
-+     bb5: {
+      bb6: {
           unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
       }
   
--     bb7: {
-+     bb6: {
+      bb7: {
           StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
           _9 = ((_2 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
           StorageLive(_10);                // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
           _10 = _9;                        // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
-          Deinit(_0);                      // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-          ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-          discriminant(_0) = 1;            // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
+          _0 = Option::<i32>::Some(move _10); // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
           StorageDead(_10);                // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44
           StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
--         goto -> bb8;                     // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
-+         goto -> bb7;                     // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
+          goto -> bb8;                     // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
       }
   
--     bb8: {
-+     bb7: {
+      bb8: {
           StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2
           return;                          // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2
       }
index 760f48d956d6288b3d72ea8edc06ed83e0e3ed90..66ba4df767ccf2ff004604ac17d3070affa706c1 100644 (file)
@@ -8,12 +8,12 @@ fn ezmap(_1: Option<i32>) -> Option<i32> {
         debug slf => _1;                 // in scope 1 at $DIR/simple_option_map_e2e.rs:2:17: 2:20
         debug f => _2;                   // in scope 1 at $DIR/simple_option_map_e2e.rs:2:33: 2:34
         let mut _3: isize;               // in scope 1 at $DIR/simple_option_map_e2e.rs:7:9: 7:16
-        let mut _4: i32;                 // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+        let _4: i32;                     // in scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
         let mut _5: i32;                 // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
         scope 2 {
-            debug x => _5;               // in scope 2 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+            debug x => _4;               // in scope 2 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
             scope 3 (inlined ezmap::{closure#0}) { // at $DIR/simple_option_map_e2e.rs:7:25: 7:29
-                debug n => _5;           // in scope 3 at $DIR/simple_option_map_e2e.rs:+1:13: +1:14
+                debug n => _4;           // in scope 3 at $DIR/simple_option_map_e2e.rs:+1:13: +1:14
             }
         }
     }
@@ -25,8 +25,7 @@ fn ezmap(_1: Option<i32>) -> Option<i32> {
     }
 
     bb1: {
-        Deinit(_0);                      // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
-        discriminant(_0) = 0;            // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+        _0 = Option::<i32>::None;        // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
         goto -> bb4;                     // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
     }
 
@@ -35,13 +34,11 @@ 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(_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
-        StorageDead(_4);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:29: 7:30
+        _4 = ((_1 as Some).0: i32);      // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+        StorageLive(_5);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+        _5 = Add(_4, const 1_i32);       // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
+        _0 = Option::<i32>::Some(move _5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+        StorageDead(_5);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:29: 7:30
         goto -> bb4;                     // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2
     }
 
index 9817380301862f9d5aeffb9b83d220babdccc957..946595e322e1889c1889d834acdbd1745fc683d4 100644 (file)
@@ -9,8 +9,7 @@
   
       bb0: {
 -         StorageLive(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
--         Deinit(_1);                      // scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
--         discriminant(_1) = 0;            // scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
+-         _1 = E::A;                       // scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
 -         StorageDead(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:17: +2:18
           _0 = const ();                   // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
           return;                          // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
index b152dc8cca3a9ce12a2697a455e4eedd6f672435..6a5dc56e211ce59b007e7ed26ee6c65e57aaf2a0 100644 (file)
@@ -9,15 +9,11 @@
   
       bb0: {
 -         StorageLive(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
--         Deinit(_1);                      // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
--         discriminant(_1) = 1;            // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
+-         _1 = E::B;                       // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
 -         StorageLive(_2);                 // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
 -         StorageLive(_3);                 // scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
--         Deinit(_3);                      // scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
--         discriminant(_3) = 0;            // scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
--         Deinit(_2);                      // scope 0 at $DIR/simplify_locals.rs:+2:6: +2:16
--         (_2.0: i32) = const 10_i32;      // scope 0 at $DIR/simplify_locals.rs:+2:6: +2:16
--         (_2.1: E) = move _3;             // scope 0 at $DIR/simplify_locals.rs:+2:6: +2:16
+-         _3 = E::A;                       // scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
+-         _2 = (const 10_i32, move _3);    // scope 0 at $DIR/simplify_locals.rs:+2:6: +2:16
 -         StorageDead(_3);                 // scope 0 at $DIR/simplify_locals.rs:+2:15: +2:16
 -         (_2.1: E) = move _1;             // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:26
 -         StorageDead(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:25: +2:26
index f888c622d90856b46ec46cb31df263ae65de58cf..9b7dd733820344ffe78e7db64e1445947b934f5c 100644 (file)
       bb0: {
           StorageLive(_1);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
           StorageLive(_2);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
-          Deinit(_2);                      // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
-          discriminant(_2) = 0;            // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
+          _2 = Option::<u8>::None;         // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
           StorageLive(_3);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
-          Deinit(_3);                      // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
-          discriminant(_3) = 0;            // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
-          Deinit(_1);                      // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
-          (_1.0: std::option::Option<u8>) = move _2; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
-          (_1.1: std::option::Option<T>) = move _3; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
+          _3 = Option::<T>::None;          // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
+          _1 = (move _2, move _3);         // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
           StorageDead(_3);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
           StorageDead(_2);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
           _5 = discriminant((_1.0: std::option::Option<u8>)); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
index efb2b0961cc1dee2e05fe83e5bffe67ca8ac7303..0f8866f9c2f4eecfa9b91b76dea8df0b5a19347e 100644 (file)
       bb0: {
 -         StorageLive(_1);                 // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
 -         StorageLive(_2);                 // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
--         Deinit(_2);                      // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
+-         _2 = ();                         // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
 -         StorageLive(_3);                 // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
--         Deinit(_3);                      // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
--         Deinit(_1);                      // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
--         (_1.0: ()) = move _2;            // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
--         (_1.1: ()) = move _3;            // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
+-         _3 = ();                         // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
+-         _1 = (move _2, move _3);         // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
 -         StorageDead(_3);                 // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:27: +1:28
 -         StorageDead(_2);                 // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:27: +1:28
 -         StorageDead(_1);                 // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:28: +1:29
 -         StorageLive(_4);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
 -         StorageLive(_5);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
 -         StorageLive(_6);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
--         Deinit(_6);                      // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
+-         _6 = ();                         // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
 -         StorageLive(_7);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
--         Deinit(_7);                      // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
--         Deinit(_5);                      // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
--         (_5.0: ()) = move _6;            // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
--         (_5.1: ()) = move _7;            // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
+-         _7 = ();                         // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
+-         _5 = (move _6, move _7);         // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
 -         StorageDead(_7);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
 -         StorageDead(_6);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
 -         _4 = use_zst(move _5) -> bb1;    // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
 +         StorageLive(_1);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
 +         StorageLive(_2);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
 +         StorageLive(_3);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
-+         Deinit(_3);                      // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
++         _3 = ();                         // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
 +         StorageLive(_4);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
-+         Deinit(_4);                      // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
-+         Deinit(_2);                      // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
-+         (_2.0: ()) = move _3;            // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
-+         (_2.1: ()) = move _4;            // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
++         _4 = ();                         // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
++         _2 = (move _3, move _4);         // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
 +         StorageDead(_4);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
 +         StorageDead(_3);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
 +         _1 = use_zst(move _2) -> bb1;    // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
@@ -73,8 +67,7 @@
 -         StorageLive(_9);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
 -         StorageLive(_10);                // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
 -         StorageLive(_11);                // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
--         Deinit(_11);                     // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
--         (_11.0: u8) = const 40_u8;       // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
+-         _11 = Temp { x: const 40_u8 };   // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
 -         _10 = (_11.0: u8);               // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
 -         _9 = Add(move _10, const 2_u8);  // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
 -         StorageDead(_10);                // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:33: +4:34
@@ -85,8 +78,7 @@
 +         StorageLive(_6);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
 +         StorageLive(_7);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
 +         StorageLive(_8);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
-+         Deinit(_8);                      // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
-+         (_8.0: u8) = const 40_u8;        // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
++         _8 = Temp { x: const 40_u8 };    // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
 +         _7 = (_8.0: u8);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
 +         _6 = Add(move _7, const 2_u8);   // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
 +         StorageDead(_7);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:33: +4:34
index 027c983e6b4c80c263638ec60433915717dfa9f7..3f9af31d888e325fe26b9dbda79a6aa3d2a7a486 100644 (file)
@@ -26,9 +26,7 @@
           _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
           StorageLive(_4);                 // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:25: +3:26
           _4 = move _3;                    // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:25: +3:26
-          Deinit(_0);                      // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:20: +3:27
-          ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:20: +3:27
-          discriminant(_0) = 1;            // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:20: +3:27
+          _0 = Option::<Box<()>>::Some(move _4); // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:20: +3:27
           StorageDead(_4);                 // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:26: +3:27
           StorageDead(_3);                 // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:26: +3:27
           goto -> bb4;                     // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:26: +3:27
@@ -39,8 +37,7 @@
       }
   
       bb3: {
-          Deinit(_0);                      // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
-          discriminant(_0) = 0;            // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
+          _0 = Option::<Box<()>>::None;    // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
           goto -> bb4;                     // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
       }
   
diff --git a/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff
new file mode 100644 (file)
index 0000000..976f6d4
--- /dev/null
@@ -0,0 +1,91 @@
+- // MIR for `copies` before ScalarReplacementOfAggregates
++ // MIR for `copies` after ScalarReplacementOfAggregates
+  
+  fn copies(_1: Foo) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/sroa.rs:+0:11: +0:12
+      let mut _0: ();                      // return place in scope 0 at $DIR/sroa.rs:+0:19: +0:19
+      let _2: Foo;                         // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
++     let _11: u8;                         // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
++     let _12: ();                         // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
++     let _13: &str;                       // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
++     let _14: std::option::Option<isize>; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
+      scope 1 {
+-         debug y => _2;                   // in scope 1 at $DIR/sroa.rs:+1:9: +1:10
++         debug y => Foo{ .0 => _11, .1 => _12, .2 => _13, .3 => _14, }; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10
+          let _3: u8;                      // in scope 1 at $DIR/sroa.rs:+2:9: +2:10
+          scope 2 {
+              debug t => _3;               // in scope 2 at $DIR/sroa.rs:+2:9: +2:10
+              let _4: &str;                // in scope 2 at $DIR/sroa.rs:+3:9: +3:10
+              scope 3 {
+                  debug u => _4;           // in scope 3 at $DIR/sroa.rs:+3:9: +3:10
+                  let _5: Foo;             // in scope 3 at $DIR/sroa.rs:+4:9: +4:10
++                 let _7: u8;              // in scope 3 at $DIR/sroa.rs:+4:9: +4:10
++                 let _8: ();              // in scope 3 at $DIR/sroa.rs:+4:9: +4:10
++                 let _9: &str;            // in scope 3 at $DIR/sroa.rs:+4:9: +4:10
++                 let _10: std::option::Option<isize>; // in scope 3 at $DIR/sroa.rs:+4:9: +4:10
+                  scope 4 {
+-                     debug z => _5;       // in scope 4 at $DIR/sroa.rs:+4:9: +4:10
++                     debug z => Foo{ .0 => _7, .1 => _8, .2 => _9, .3 => _10, }; // in scope 4 at $DIR/sroa.rs:+4:9: +4:10
+                      let _6: ();          // in scope 4 at $DIR/sroa.rs:+5:9: +5:10
+                      scope 5 {
+                          debug a => _6;   // in scope 5 at $DIR/sroa.rs:+5:9: +5:10
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_2);                 // scope 0 at $DIR/sroa.rs:+1:9: +1:10
+-         _2 = _1;                         // scope 0 at $DIR/sroa.rs:+1:13: +1:14
++         StorageLive(_11);                // scope 0 at $DIR/sroa.rs:+1:9: +1:10
++         StorageLive(_12);                // scope 0 at $DIR/sroa.rs:+1:9: +1:10
++         StorageLive(_13);                // scope 0 at $DIR/sroa.rs:+1:9: +1:10
++         StorageLive(_14);                // scope 0 at $DIR/sroa.rs:+1:9: +1:10
++         nop;                             // scope 0 at $DIR/sroa.rs:+1:9: +1:10
++         _11 = (_1.0: u8);                // scope 0 at $DIR/sroa.rs:+1:13: +1:14
++         _12 = (_1.1: ());                // scope 0 at $DIR/sroa.rs:+1:13: +1:14
++         _13 = (_1.2: &str);              // scope 0 at $DIR/sroa.rs:+1:13: +1:14
++         _14 = (_1.3: std::option::Option<isize>); // scope 0 at $DIR/sroa.rs:+1:13: +1:14
++         nop;                             // scope 0 at $DIR/sroa.rs:+1:13: +1:14
+          StorageLive(_3);                 // scope 1 at $DIR/sroa.rs:+2:9: +2:10
+-         _3 = (_2.0: u8);                 // scope 1 at $DIR/sroa.rs:+2:13: +2:16
++         _3 = _11;                        // scope 1 at $DIR/sroa.rs:+2:13: +2:16
+          StorageLive(_4);                 // scope 2 at $DIR/sroa.rs:+3:9: +3:10
+-         _4 = (_2.2: &str);               // scope 2 at $DIR/sroa.rs:+3:13: +3:16
+-         StorageLive(_5);                 // scope 3 at $DIR/sroa.rs:+4:9: +4:10
+-         _5 = _2;                         // scope 3 at $DIR/sroa.rs:+4:13: +4:14
++         _4 = _13;                        // scope 2 at $DIR/sroa.rs:+3:13: +3:16
++         StorageLive(_7);                 // scope 3 at $DIR/sroa.rs:+4:9: +4:10
++         StorageLive(_8);                 // scope 3 at $DIR/sroa.rs:+4:9: +4:10
++         StorageLive(_9);                 // scope 3 at $DIR/sroa.rs:+4:9: +4:10
++         StorageLive(_10);                // scope 3 at $DIR/sroa.rs:+4:9: +4:10
++         nop;                             // scope 3 at $DIR/sroa.rs:+4:9: +4:10
++         _7 = _11;                        // scope 3 at $DIR/sroa.rs:+4:13: +4:14
++         _8 = _12;                        // scope 3 at $DIR/sroa.rs:+4:13: +4:14
++         _9 = _13;                        // scope 3 at $DIR/sroa.rs:+4:13: +4:14
++         _10 = _14;                       // scope 3 at $DIR/sroa.rs:+4:13: +4:14
++         nop;                             // scope 3 at $DIR/sroa.rs:+4:13: +4:14
+          StorageLive(_6);                 // scope 4 at $DIR/sroa.rs:+5:9: +5:10
+-         _6 = (_5.1: ());                 // scope 4 at $DIR/sroa.rs:+5:13: +5:16
++         _6 = _8;                         // scope 4 at $DIR/sroa.rs:+5:13: +5:16
+          _0 = const ();                   // scope 0 at $DIR/sroa.rs:+0:19: +6:2
+          StorageDead(_6);                 // scope 4 at $DIR/sroa.rs:+6:1: +6:2
+-         StorageDead(_5);                 // scope 3 at $DIR/sroa.rs:+6:1: +6:2
++         StorageDead(_7);                 // scope 3 at $DIR/sroa.rs:+6:1: +6:2
++         StorageDead(_8);                 // scope 3 at $DIR/sroa.rs:+6:1: +6:2
++         StorageDead(_9);                 // scope 3 at $DIR/sroa.rs:+6:1: +6:2
++         StorageDead(_10);                // scope 3 at $DIR/sroa.rs:+6:1: +6:2
++         nop;                             // scope 3 at $DIR/sroa.rs:+6:1: +6:2
+          StorageDead(_4);                 // scope 2 at $DIR/sroa.rs:+6:1: +6:2
+          StorageDead(_3);                 // scope 1 at $DIR/sroa.rs:+6:1: +6:2
+-         StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+6:1: +6:2
++         StorageDead(_11);                // scope 0 at $DIR/sroa.rs:+6:1: +6:2
++         StorageDead(_12);                // scope 0 at $DIR/sroa.rs:+6:1: +6:2
++         StorageDead(_13);                // scope 0 at $DIR/sroa.rs:+6:1: +6:2
++         StorageDead(_14);                // scope 0 at $DIR/sroa.rs:+6:1: +6:2
++         nop;                             // scope 0 at $DIR/sroa.rs:+6:1: +6:2
+          return;                          // scope 0 at $DIR/sroa.rs:+6:2: +6:2
+      }
+  }
+  
index eb88304466eec67c0302d88fbe2b20d00d5a1269..17a89e7d8eb204c2fc4280ee829e0ada254671af 100644 (file)
           StorageLive(_1);                 // scope 0 at $DIR/sroa.rs:+1:5: +1:32
           StorageLive(_2);                 // scope 0 at $DIR/sroa.rs:+1:5: +1:30
           StorageLive(_3);                 // scope 0 at $DIR/sroa.rs:+1:7: +1:13
-          Deinit(_3);                      // scope 0 at $DIR/sroa.rs:+1:7: +1:13
-          (_3.0: usize) = const 0_usize;   // scope 0 at $DIR/sroa.rs:+1:7: +1:13
+          _3 = Tag(const 0_usize);         // scope 0 at $DIR/sroa.rs:+1:7: +1:13
           StorageLive(_4);                 // scope 0 at $DIR/sroa.rs:+1:15: +1:21
-          Deinit(_4);                      // scope 0 at $DIR/sroa.rs:+1:15: +1:21
-          (_4.0: usize) = const 1_usize;   // scope 0 at $DIR/sroa.rs:+1:15: +1:21
+          _4 = Tag(const 1_usize);         // scope 0 at $DIR/sroa.rs:+1:15: +1:21
           StorageLive(_5);                 // scope 0 at $DIR/sroa.rs:+1:23: +1:29
-          Deinit(_5);                      // scope 0 at $DIR/sroa.rs:+1:23: +1:29
-          (_5.0: usize) = const 2_usize;   // scope 0 at $DIR/sroa.rs:+1:23: +1:29
-          Deinit(_2);                      // scope 0 at $DIR/sroa.rs:+1:5: +1:30
-          (_2.0: Tag) = move _3;           // scope 0 at $DIR/sroa.rs:+1:5: +1:30
-          (_2.1: Tag) = move _4;           // scope 0 at $DIR/sroa.rs:+1:5: +1:30
-          (_2.2: Tag) = move _5;           // scope 0 at $DIR/sroa.rs:+1:5: +1:30
+          _5 = Tag(const 2_usize);         // scope 0 at $DIR/sroa.rs:+1:23: +1:29
+          _2 = S(move _3, move _4, move _5); // scope 0 at $DIR/sroa.rs:+1:5: +1:30
           StorageDead(_5);                 // scope 0 at $DIR/sroa.rs:+1:29: +1:30
           StorageDead(_4);                 // scope 0 at $DIR/sroa.rs:+1:29: +1:30
           StorageDead(_3);                 // scope 0 at $DIR/sroa.rs:+1:29: +1:30
index a5488c1ec7bfee1f31c4ae7fc8d7ab3331b345ab..04d26162aadef88a0a3f63c0257c461879e6bd47 100644 (file)
@@ -16,9 +16,7 @@
           StorageLive(_2);                 // scope 1 at $DIR/sroa.rs:+1:22: +1:29
           StorageLive(_3);                 // scope 1 at $DIR/sroa.rs:+1:27: +1:28
           _3 = _1;                         // scope 1 at $DIR/sroa.rs:+1:27: +1:28
-          Deinit(_2);                      // scope 1 at $DIR/sroa.rs:+1:22: +1:29
-          ((_2 as Some).0: usize) = move _3; // scope 1 at $DIR/sroa.rs:+1:22: +1:29
-          discriminant(_2) = 1;            // scope 1 at $DIR/sroa.rs:+1:22: +1:29
+          _2 = Option::<usize>::Some(move _3); // scope 1 at $DIR/sroa.rs:+1:22: +1:29
           StorageDead(_3);                 // scope 1 at $DIR/sroa.rs:+1:28: +1:29
           _4 = discriminant(_2);           // scope 1 at $DIR/sroa.rs:+1:12: +1:19
           switchInt(move _4) -> [1: bb1, otherwise: bb2]; // scope 1 at $DIR/sroa.rs:+1:12: +1:19
index 64559b58f61f3b3520001e4b73b534d177aeec11..ea7f5007224519e16759e5054db50242eb790155 100644 (file)
           StorageLive(_5);                 // scope 0 at $DIR/sroa.rs:+2:34: +2:37
           _5 = g() -> bb1;                 // scope 0 at $DIR/sroa.rs:+2:34: +2:37
                                            // mir::Constant
-                                           // + span: $DIR/sroa.rs:78:34: 78:35
+                                           // + span: $DIR/sroa.rs:73:34: 73:35
                                            // + literal: Const { ty: fn() -> u32 {g}, val: Value(<ZST>) }
       }
   
       bb1: {
-          Deinit(_4);                      // scope 0 at $DIR/sroa.rs:+2:8: +2:39
-          (_4.0: u32) = const 1_u32;       // scope 0 at $DIR/sroa.rs:+2:8: +2:39
-          (_4.1: u32) = const 2_u32;       // scope 0 at $DIR/sroa.rs:+2:8: +2:39
-          (_4.2: u32) = move _5;           // scope 0 at $DIR/sroa.rs:+2:8: +2:39
+          _4 = Escaping { a: const 1_u32, b: const 2_u32, c: move _5 }; // scope 0 at $DIR/sroa.rs:+2:8: +2:39
           StorageDead(_5);                 // scope 0 at $DIR/sroa.rs:+2:38: +2:39
           _3 = &(_4.0: u32);               // scope 0 at $DIR/sroa.rs:+2:7: +2:41
           _2 = &raw const (*_3);           // scope 0 at $DIR/sroa.rs:+2:7: +2:41
           _1 = f(move _2) -> bb2;          // scope 0 at $DIR/sroa.rs:+2:5: +2:42
                                            // mir::Constant
-                                           // + span: $DIR/sroa.rs:78:5: 78:6
+                                           // + span: $DIR/sroa.rs:73:5: 73:6
                                            // + literal: Const { ty: fn(*const u32) {f}, val: Value(<ZST>) }
       }
   
index d4c04d5e68b8a269cfdae7158e92a89f469e8660..69631fc0213f8f5d31ab407509bdc3beb14adf2d 100644 (file)
 +         StorageLive(_9);                 // scope 0 at $DIR/sroa.rs:+1:30: +1:70
 +         StorageLive(_10);                // scope 0 at $DIR/sroa.rs:+1:30: +1:70
 +         StorageLive(_11);                // scope 0 at $DIR/sroa.rs:+1:30: +1:70
++         nop;                             // scope 0 at $DIR/sroa.rs:+1:30: +1:70
           StorageLive(_6);                 // scope 0 at $DIR/sroa.rs:+1:45: +1:47
-          Deinit(_6);                      // scope 0 at $DIR/sroa.rs:+1:45: +1:47
+          _6 = ();                         // scope 0 at $DIR/sroa.rs:+1:45: +1:47
           StorageLive(_7);                 // scope 0 at $DIR/sroa.rs:+1:60: +1:68
-          Deinit(_7);                      // scope 0 at $DIR/sroa.rs:+1:60: +1:68
-          ((_7 as Some).0: isize) = const -4_isize; // scope 0 at $DIR/sroa.rs:+1:60: +1:68
-          discriminant(_7) = 1;            // scope 0 at $DIR/sroa.rs:+1:60: +1:68
--         Deinit(_5);                      // scope 0 at $DIR/sroa.rs:+1:30: +1:70
--         (_5.0: u8) = const 5_u8;         // scope 0 at $DIR/sroa.rs:+1:30: +1:70
--         (_5.1: ()) = move _6;            // scope 0 at $DIR/sroa.rs:+1:30: +1:70
--         (_5.2: &str) = const "a";        // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+         Deinit(_8);                      // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+         Deinit(_9);                      // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+         Deinit(_10);                     // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+         Deinit(_11);                     // scope 0 at $DIR/sroa.rs:+1:30: +1:70
+          _7 = Option::<isize>::Some(const -4_isize); // scope 0 at $DIR/sroa.rs:+1:60: +1:68
+-         _5 = Foo { a: const 5_u8, b: move _6, c: const "a", d: move _7 }; // scope 0 at $DIR/sroa.rs:+1:30: +1:70
 +         _8 = const 5_u8;                 // scope 0 at $DIR/sroa.rs:+1:30: +1:70
 +         _9 = move _6;                    // scope 0 at $DIR/sroa.rs:+1:30: +1:70
 +         _10 = const "a";                 // scope 0 at $DIR/sroa.rs:+1:30: +1:70
                                            // mir::Constant
-                                           // + span: $DIR/sroa.rs:57:52: 57:55
+                                           // + span: $DIR/sroa.rs:53:52: 53:55
                                            // + literal: Const { ty: &str, val: Value(Slice(..)) }
--         (_5.3: std::option::Option<isize>) = move _7; // scope 0 at $DIR/sroa.rs:+1:30: +1:70
 +         _11 = move _7;                   // scope 0 at $DIR/sroa.rs:+1:30: +1:70
++         nop;                             // scope 0 at $DIR/sroa.rs:+1:30: +1:70
           StorageDead(_7);                 // scope 0 at $DIR/sroa.rs:+1:69: +1:70
           StorageDead(_6);                 // scope 0 at $DIR/sroa.rs:+1:69: +1:70
           StorageLive(_1);                 // scope 0 at $DIR/sroa.rs:+1:15: +1:16
@@ -76,6 +68,7 @@
 +         StorageDead(_9);                 // scope 0 at $DIR/sroa.rs:+1:70: +1:71
 +         StorageDead(_10);                // scope 0 at $DIR/sroa.rs:+1:70: +1:71
 +         StorageDead(_11);                // scope 0 at $DIR/sroa.rs:+1:70: +1:71
++         nop;                             // scope 0 at $DIR/sroa.rs:+1:70: +1:71
           _0 = const ();                   // scope 0 at $DIR/sroa.rs:+0:15: +6:2
           StorageDead(_4);                 // scope 0 at $DIR/sroa.rs:+6:1: +6:2
           StorageDead(_3);                 // scope 0 at $DIR/sroa.rs:+6:1: +6:2
diff --git a/tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff
new file mode 100644 (file)
index 0000000..f0d6222
--- /dev/null
@@ -0,0 +1,56 @@
+- // MIR for `ref_copies` before ScalarReplacementOfAggregates
++ // MIR for `ref_copies` after ScalarReplacementOfAggregates
+  
+  fn ref_copies(_1: &Foo) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/sroa.rs:+0:15: +0:16
+      let mut _0: ();                      // return place in scope 0 at $DIR/sroa.rs:+0:24: +0:24
+      let _2: Foo;                         // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
++     let _5: u8;                          // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
++     let _6: ();                          // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
++     let _7: &str;                        // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
++     let _8: std::option::Option<isize>;  // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
+      scope 1 {
+-         debug y => _2;                   // in scope 1 at $DIR/sroa.rs:+1:9: +1:10
++         debug y => Foo{ .0 => _5, .1 => _6, .2 => _7, .3 => _8, }; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10
+          let _3: u8;                      // in scope 1 at $DIR/sroa.rs:+2:9: +2:10
+          scope 2 {
+              debug t => _3;               // in scope 2 at $DIR/sroa.rs:+2:9: +2:10
+              let _4: &str;                // in scope 2 at $DIR/sroa.rs:+3:9: +3:10
+              scope 3 {
+                  debug u => _4;           // in scope 3 at $DIR/sroa.rs:+3:9: +3:10
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_2);                 // scope 0 at $DIR/sroa.rs:+1:9: +1:10
+-         _2 = (*_1);                      // scope 0 at $DIR/sroa.rs:+1:13: +1:15
++         StorageLive(_5);                 // scope 0 at $DIR/sroa.rs:+1:9: +1:10
++         StorageLive(_6);                 // scope 0 at $DIR/sroa.rs:+1:9: +1:10
++         StorageLive(_7);                 // scope 0 at $DIR/sroa.rs:+1:9: +1:10
++         StorageLive(_8);                 // scope 0 at $DIR/sroa.rs:+1:9: +1:10
++         nop;                             // scope 0 at $DIR/sroa.rs:+1:9: +1:10
++         _5 = ((*_1).0: u8);              // scope 0 at $DIR/sroa.rs:+1:13: +1:15
++         _6 = ((*_1).1: ());              // scope 0 at $DIR/sroa.rs:+1:13: +1:15
++         _7 = ((*_1).2: &str);            // scope 0 at $DIR/sroa.rs:+1:13: +1:15
++         _8 = ((*_1).3: std::option::Option<isize>); // scope 0 at $DIR/sroa.rs:+1:13: +1:15
++         nop;                             // scope 0 at $DIR/sroa.rs:+1:13: +1:15
+          StorageLive(_3);                 // scope 1 at $DIR/sroa.rs:+2:9: +2:10
+-         _3 = (_2.0: u8);                 // scope 1 at $DIR/sroa.rs:+2:13: +2:16
++         _3 = _5;                         // scope 1 at $DIR/sroa.rs:+2:13: +2:16
+          StorageLive(_4);                 // scope 2 at $DIR/sroa.rs:+3:9: +3:10
+-         _4 = (_2.2: &str);               // scope 2 at $DIR/sroa.rs:+3:13: +3:16
++         _4 = _7;                         // scope 2 at $DIR/sroa.rs:+3:13: +3:16
+          _0 = const ();                   // scope 0 at $DIR/sroa.rs:+0:24: +4:2
+          StorageDead(_4);                 // scope 2 at $DIR/sroa.rs:+4:1: +4:2
+          StorageDead(_3);                 // scope 1 at $DIR/sroa.rs:+4:1: +4:2
+-         StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+4:1: +4:2
++         StorageDead(_5);                 // scope 0 at $DIR/sroa.rs:+4:1: +4:2
++         StorageDead(_6);                 // scope 0 at $DIR/sroa.rs:+4:1: +4:2
++         StorageDead(_7);                 // scope 0 at $DIR/sroa.rs:+4:1: +4:2
++         StorageDead(_8);                 // scope 0 at $DIR/sroa.rs:+4:1: +4:2
++         nop;                             // scope 0 at $DIR/sroa.rs:+4:1: +4:2
+          return;                          // scope 0 at $DIR/sroa.rs:+4:2: +4:2
+      }
+  }
+  
index ff8deb40d7d5a388c74f71102ae489834ad3a2e3..471aac9f9d82d2b5103b14cacff71ba9f10ecfbe 100644 (file)
@@ -12,17 +12,14 @@ impl Drop for Tag {
     fn drop(&mut self) {}
 }
 
-// EMIT_MIR sroa.dropping.ScalarReplacementOfAggregates.diff
 pub fn dropping() {
     S(Tag(0), Tag(1), Tag(2)).1;
 }
 
-// EMIT_MIR sroa.enums.ScalarReplacementOfAggregates.diff
 pub fn enums(a: usize) -> usize {
     if let Some(a) = Some(a) { a } else { 0 }
 }
 
-// EMIT_MIR sroa.structs.ScalarReplacementOfAggregates.diff
 pub fn structs(a: f32) -> f32 {
     struct U {
         _foo: usize,
@@ -32,7 +29,6 @@ struct U {
     U { _foo: 0, a }.a
 }
 
-// EMIT_MIR sroa.unions.ScalarReplacementOfAggregates.diff
 pub fn unions(a: f32) -> u32 {
     union Repr {
         f: f32,
@@ -41,6 +37,7 @@ union Repr {
     unsafe { Repr { f: a }.u }
 }
 
+#[derive(Copy, Clone)]
 struct Foo {
     a: u8,
     b: (),
@@ -52,7 +49,6 @@ fn g() -> u32 {
     3
 }
 
-// EMIT_MIR sroa.flat.ScalarReplacementOfAggregates.diff
 pub fn flat() {
     let Foo { a, b, c, d } = Foo { a: 5, b: (), c: "a", d: Some(-4) };
     let _ = a;
@@ -72,12 +68,25 @@ fn f(a: *const u32) {
     println!("{}", unsafe { *a.add(2) });
 }
 
-// EMIT_MIR sroa.escaping.ScalarReplacementOfAggregates.diff
 pub fn escaping() {
     // Verify this struct is not flattened.
     f(&Escaping { a: 1, b: 2, c: g() }.a);
 }
 
+fn copies(x: Foo) {
+    let y = x;
+    let t = y.a;
+    let u = y.c;
+    let z = y;
+    let a = z.b;
+}
+
+fn ref_copies(x: &Foo) {
+    let y = *x;
+    let t = y.a;
+    let u = y.c;
+}
+
 fn main() {
     dropping();
     enums(5);
@@ -85,4 +94,15 @@ fn main() {
     unions(5.);
     flat();
     escaping();
+    copies(Foo { a: 5, b: (), c: "a", d: Some(-4) });
+    ref_copies(&Foo { a: 5, b: (), c: "a", d: Some(-4) });
 }
+
+// EMIT_MIR sroa.dropping.ScalarReplacementOfAggregates.diff
+// EMIT_MIR sroa.enums.ScalarReplacementOfAggregates.diff
+// EMIT_MIR sroa.structs.ScalarReplacementOfAggregates.diff
+// EMIT_MIR sroa.unions.ScalarReplacementOfAggregates.diff
+// EMIT_MIR sroa.flat.ScalarReplacementOfAggregates.diff
+// EMIT_MIR sroa.escaping.ScalarReplacementOfAggregates.diff
+// EMIT_MIR sroa.copies.ScalarReplacementOfAggregates.diff
+// EMIT_MIR sroa.ref_copies.ScalarReplacementOfAggregates.diff
index 69d74c351deccd5892486423efd4c1fda8a7a0b3..2c63d8b266dde9fffcfe0c1fb57c5fe98fcdb867 100644 (file)
 -         StorageLive(_2);                 // scope 0 at $DIR/sroa.rs:+6:5: +6:21
 +         StorageLive(_4);                 // scope 0 at $DIR/sroa.rs:+6:5: +6:21
 +         StorageLive(_5);                 // scope 0 at $DIR/sroa.rs:+6:5: +6:21
++         nop;                             // scope 0 at $DIR/sroa.rs:+6:5: +6:21
           StorageLive(_3);                 // scope 0 at $DIR/sroa.rs:+6:18: +6:19
           _3 = _1;                         // scope 0 at $DIR/sroa.rs:+6:18: +6:19
--         Deinit(_2);                      // scope 0 at $DIR/sroa.rs:+6:5: +6:21
--         (_2.0: usize) = const 0_usize;   // scope 0 at $DIR/sroa.rs:+6:5: +6:21
--         (_2.1: f32) = move _3;           // scope 0 at $DIR/sroa.rs:+6:5: +6:21
-+         Deinit(_4);                      // scope 0 at $DIR/sroa.rs:+6:5: +6:21
-+         Deinit(_5);                      // scope 0 at $DIR/sroa.rs:+6:5: +6:21
+-         _2 = U { _foo: const 0_usize, a: move _3 }; // scope 0 at $DIR/sroa.rs:+6:5: +6:21
 +         _4 = const 0_usize;              // scope 0 at $DIR/sroa.rs:+6:5: +6:21
 +         _5 = move _3;                    // scope 0 at $DIR/sroa.rs:+6:5: +6:21
++         nop;                             // scope 0 at $DIR/sroa.rs:+6:5: +6:21
           StorageDead(_3);                 // scope 0 at $DIR/sroa.rs:+6:20: +6:21
 -         _0 = (_2.1: f32);                // scope 0 at $DIR/sroa.rs:+6:5: +6:23
 -         StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+7:1: +7:2
 +         _0 = _5;                         // scope 0 at $DIR/sroa.rs:+6:5: +6:23
 +         StorageDead(_4);                 // scope 0 at $DIR/sroa.rs:+7:1: +7:2
 +         StorageDead(_5);                 // scope 0 at $DIR/sroa.rs:+7:1: +7:2
++         nop;                             // scope 0 at $DIR/sroa.rs:+7:1: +7:2
           return;                          // scope 0 at $DIR/sroa.rs:+7:2: +7:2
       }
   }
index 03ca976df7be68d5cd77634408052d1c0fb4fee1..adfb01385d448abaaf08bce5ed8279067a237a0c 100644 (file)
@@ -13,8 +13,7 @@
           StorageLive(_2);                 // scope 1 at $DIR/sroa.rs:+5:14: +5:27
           StorageLive(_3);                 // scope 1 at $DIR/sroa.rs:+5:24: +5:25
           _3 = _1;                         // scope 1 at $DIR/sroa.rs:+5:24: +5:25
-          Deinit(_2);                      // scope 1 at $DIR/sroa.rs:+5:14: +5:27
-          (_2.0: f32) = move _3;           // scope 1 at $DIR/sroa.rs:+5:14: +5:27
+          _2 = Repr { f: move _3 };        // scope 1 at $DIR/sroa.rs:+5:14: +5:27
           StorageDead(_3);                 // scope 1 at $DIR/sroa.rs:+5:26: +5:27
           _0 = (_2.1: u32);                // scope 1 at $DIR/sroa.rs:+5:14: +5:29
           StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+6:1: +6:2
index a4d2660ca6aeb54ff421adcb22bbd51462ab335b..b9cc1057513d08670528189998ac5af3ed236710 100644 (file)
@@ -26,45 +26,40 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
     bb0: {
         StorageLive(_2);                 // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
         _3 = discriminant(_1);           // scope 0 at $DIR/try_identity_e2e.rs:+3:19: +3:20
-        switchInt(move _3) -> [0: bb2, 1: bb1, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:20
+        switchInt(move _3) -> [0: bb2, 1: bb1, otherwise: bb5]; // scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:20
     }
 
     bb1: {
         _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
-        discriminant(_2) = 1;            // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
-        _6 = discriminant(_2);           // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
-        switchInt(move _6) -> [0: bb5, 1: bb3, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +7:10
+        _2 = ControlFlow::<E, T>::Break(move _5); // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
+        goto -> bb3;                     // scope 0 at $DIR/try_identity_e2e.rs:+5:47: +5:48
     }
 
     bb2: {
         _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
-        discriminant(_2) = 0;            // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
-        _6 = discriminant(_2);           // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
-        switchInt(move _6) -> [0: bb5, 1: bb3, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +7:10
+        _2 = ControlFlow::<E, T>::Continue(move _4); // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
+        goto -> bb3;                     // scope 0 at $DIR/try_identity_e2e.rs:+4:49: +4:50
     }
 
     bb3: {
+        _6 = discriminant(_2);           // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
+        switchInt(move _6) -> [0: bb6, 1: bb4, otherwise: bb5]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +7:10
+    }
+
+    bb4: {
         _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
-        discriminant(_0) = 1;            // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
+        _0 = Result::<T, E>::Err(move _8); // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
         StorageDead(_2);                 // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
         return;                          // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
     }
 
-    bb4: {
+    bb5: {
         unreachable;                     // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
     }
 
-    bb5: {
+    bb6: {
         _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
-        discriminant(_0) = 0;            // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
+        _0 = Result::<T, E>::Ok(move _7); // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
         StorageDead(_2);                 // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
         return;                          // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
     }
index 37851c66a6076006578e735fee0b181559b75db8..d88ae5ac93eba8504d22de3bd38b486dadae2ef4 100644 (file)
@@ -20,9 +20,7 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
 
     bb1: {
         _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
-        discriminant(_0) = 1;            // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
+        _0 = Result::<T, E>::Err(move _4); // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
         return;                          // scope 0 at $DIR/try_identity_e2e.rs:+7:1: +7:2
     }
 
@@ -32,9 +30,7 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
 
     bb3: {
         _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
-        discriminant(_0) = 0;            // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
+        _0 = Result::<T, E>::Ok(move _3); // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
         return;                          // scope 0 at $DIR/try_identity_e2e.rs:+7:1: +7:2
     }
 }
index 39ec05277595518ba60e39de7973cdbb8b998c71..03f37b14b28c98f6d563630f50dea11f1eb9fe1b 100644 (file)
@@ -15,8 +15,7 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +5:6
         StorageLive(_2);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
-        Deinit(_2);                      // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
-        discriminant(_2) = 2;            // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
+        _2 = Test1::C;                   // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
         _3 = discriminant(_2);           // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
         switchInt(move _3) -> [2: bb1, otherwise: bb2]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +1:19
     }
@@ -33,8 +32,7 @@ fn main() -> () {
         StorageDead(_1);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:+5:6: +5:7
         StorageLive(_6);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +10:6
         StorageLive(_7);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
-        Deinit(_7);                      // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
-        discriminant(_7) = 0;            // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
+        _7 = Test2::D;                   // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
         _8 = discriminant(_7);           // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
         switchInt(move _8) -> [4: bb5, 5: bb3, otherwise: bb4]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +7:19
     }
index 598413a1d82de896744266987d7f71afe96793b8..671e116226bea61e20d2181f9fc5a9bc62290a39 100644 (file)
@@ -16,8 +16,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +5:6
           StorageLive(_2);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
-          Deinit(_2);                      // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
-          discriminant(_2) = 2;            // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
+          _2 = Test1::C;                   // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
           _3 = discriminant(_2);           // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
 -         switchInt(move _3) -> [0: bb3, 1: bb4, 2: bb1, otherwise: bb2]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +1:19
 +         switchInt(move _3) -> [2: bb1, otherwise: bb2]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +1:19
@@ -62,8 +61,7 @@
           StorageDead(_1);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:+5:6: +5:7
           StorageLive(_6);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +10:6
           StorageLive(_7);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
-          Deinit(_7);                      // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
-          discriminant(_7) = 0;            // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
+          _7 = Test2::D;                   // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
           _8 = discriminant(_7);           // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
           switchInt(move _8) -> [4: bb8, 5: bb6, otherwise: bb7]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +7:19
       }
index c8cd6f6c1ea1d69950ee8f65accd39fb1acdaf6f..eb2a76ed1d5e45df0545a1469bfcc1a1a13faf21 100644 (file)
@@ -22,11 +22,8 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:9: +1:13
         StorageLive(_2);                 // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46
-        Deinit(_2);                      // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46
-        discriminant(_2) = 2;            // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46
-        Deinit(_1);                      // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48
-        (_1.0: u32) = const 51_u32;      // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48
-        (_1.1: Test1) = move _2;         // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48
+        _2 = Test1::C;                   // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46
+        _1 = Plop { xx: const 51_u32, test1: move _2 }; // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48
         StorageDead(_2);                 // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:47: +1:48
         StorageLive(_3);                 // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:5: +8:6
         StorageLive(_4);                 // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22
index 2aee6d2681d642466be5cab4bb5b8b93da629ea4..4e797774dba7e6e45f2f8ca12a83f132be755dfb 100644 (file)
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:9: +1:13
           StorageLive(_2);                 // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46
-          Deinit(_2);                      // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46
-          discriminant(_2) = 2;            // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46
-          Deinit(_1);                      // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48
-          (_1.0: u32) = const 51_u32;      // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48
-          (_1.1: Test1) = move _2;         // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48
+          _2 = Test1::C;                   // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:38: +1:46
+          _1 = Plop { xx: const 51_u32, test1: move _2 }; // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:16: +1:48
           StorageDead(_2);                 // scope 0 at $DIR/uninhabited_enum_branching2.rs:+1:47: +1:48
           StorageLive(_3);                 // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:5: +8:6
           StorageLive(_4);                 // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22
index ee029676311bf25d676195340fad7a58b9e59f17..8b271135cc3f6978dfec495608a35e5d317eab72 100644 (file)
@@ -4,9 +4,7 @@ fn Test::X(_1: usize) -> Test {
     let mut _0: Test;                    // return place in scope 0 at $DIR/unusual_item_types.rs:+0:5: +0:6
 
     bb0: {
-        Deinit(_0);                      // scope 0 at $DIR/unusual_item_types.rs:+0:5: +0:6
-        ((_0 as X).0: usize) = move _1;  // scope 0 at $DIR/unusual_item_types.rs:+0:5: +0:6
-        discriminant(_0) = 0;            // scope 0 at $DIR/unusual_item_types.rs:+0:5: +0:6
+        _0 = Test::X(move _1);           // scope 0 at $DIR/unusual_item_types.rs:+0:5: +0:6
         return;                          // scope 0 at $DIR/unusual_item_types.rs:+0:5: +0:6
     }
 }
index bb1de59d4a73f0b2c059a85e312178a06ca585f1..a4f2d8c84d889f90bccdb76c1d1a84acbd6bade5 100644 (file)
@@ -16,8 +16,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
           _1 = const 0_i32;                // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19
           StorageLive(_2);                 // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-          Deinit(_2);                      // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-          discriminant(_2) = 0;            // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+          _2 = Option::<u32>::None;        // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
 -         _3 = discriminant(_2);           // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
 -         switchInt(move _3) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
 +         _3 = const 0_isize;              // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
index 51250439694b054d85f3c85110ac67ac3692a5da..6ad1e8b4f673f5d46ba103735f902469e902bdc2 100644 (file)
@@ -340,7 +340,7 @@ pub fn method() {}
 pub mod doc_block_table {
 
     pub trait DocBlockTableTrait {
-        fn func();
+        fn foo();
     }
 
     /// Struct doc.
@@ -359,7 +359,7 @@ impl DocBlockTableTrait for DocBlockTable {
         /// | header1                  | header2                  |
         /// |--------------------------|--------------------------|
         /// | Lorem Ipsum, Lorem Ipsum | Lorem Ipsum, Lorem Ipsum |
-        fn func() {
+        fn foo() {
             println!();
         }
     }
@@ -474,3 +474,15 @@ pub fn test_fn() {}
 ///
 /// </sub>
 pub mod codeblock_sub {}
+pub mod search_results {
+
+    pub struct SearchResults {
+        pub foo: i32,
+    }
+
+    #[macro_export]
+    macro_rules! foo {
+        () => {};
+    }
+
+}
diff --git a/tests/rustdoc-js-std/regex.js b/tests/rustdoc-js-std/regex.js
new file mode 100644 (file)
index 0000000..a6843c5
--- /dev/null
@@ -0,0 +1,10 @@
+// exact-check
+
+// https://github.com/rust-lang/rust/issues/103357
+const QUERY = 'regex';
+
+const EXPECTED = {
+    'others': [],
+    'in_args': [],
+    'returned': [],
+};
index fd5c5489d79cfe04a4d844cfdec619ec542719f7..eeb3e1888695953d3746b68ac2d4616af2df8248 100644 (file)
@@ -9,9 +9,5 @@ const EXPECTED = {
         { 'path': 'std', 'name': 'println' },
         { 'path': 'std', 'name': 'eprint' },
         { 'path': 'std', 'name': 'eprintln' },
-        { 'path': 'std::pin', 'name': 'pin' },
-        { 'path': 'std::future', 'name': 'join' },
-        { 'path': 'std', 'name': 'line' },
-        { 'path': 'std', 'name': 'write' },
     ],
 };
index 7bb0cbe388fee1c8d7626b2d4aa74edd9ac80d10..62c8e7a74b9405ed2a22075ec9464d189fce2228 100644 (file)
@@ -1,5 +1,3 @@
-// exact-check
-
 const QUERY = [
     'StructItem',
     'StructFieldItem',
index a446c39ebad57cdc05bb311e2f8614d32c672c90..f17a97f13dc7e9e3aaca47ab424284e28e29ad43 100644 (file)
@@ -4,6 +4,5 @@ const EXPECTED = {
     'others': [
         { 'path': 'module_substring::Sig', 'name': 'pc' },
         { 'path': 'module_substring::Si', 'name': 'pc' },
-        { 'path': 'module_substring::Si', 'name': 'pa' },
     ],
 };
index 8a636f449210f20b99993d5da8b03e19eb2d7f63..f06a20b27dce79f9f5a6e556481ebffb3f2e285d 100644 (file)
@@ -4,3 +4,15 @@ pub trait Foo {
     fn bar(&self);
     fn foo(&mut self) {}
 }
+
+pub trait Bar {
+    fn bar(&self);
+    fn foo1(&mut self) {}
+    fn foo2(&mut self) {}
+}
+
+pub trait Baz {
+    fn bar1(&self);
+    fn bar2(&self);
+    fn foo(&mut self) {}
+}
index 02b51b3446195711319d83369a393c2d7d5ac452..a2500de79a0968b37420318d6e18dbbd929cdda3 100644 (file)
@@ -1,7 +1,9 @@
 <code>pub trait Write {
+    // Required methods
     fn <a href="#tymethod.poll_write" class="fn">poll_write</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;buf: &amp;mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
 <span class="item-spacer" />    fn <a href="#tymethod.poll_flush" class="fn">poll_flush</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
 <span class="item-spacer" />    fn <a href="#tymethod.poll_close" class="fn">poll_close</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
 
+    // Provided method
     fn <a href="#method.poll_write_vectored" class="fn">poll_write_vectored</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;bufs: &amp;[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt; { ... }
-}</code>
\ No newline at end of file
+}</code>
index 384be668954000f0a61b53d43cdccd4249881487..e8f4f6000457dcaee93238ded6d67463ecf74304 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&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
+<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: &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 0cc1ee10fd33571f268e88aacd0fe54a185e8013..e7909669b150a2720e172d0079f428f88ff9199f 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&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: &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 e6468316f583b46b7f2dba066807c94b9dd89f62..7706cb139ac9444852ef2ff5d01d10ba3dd1cdc7 100644 (file)
@@ -4,6 +4,18 @@
 extern crate inline_default_methods;
 
 // @has inline_default_methods/trait.Foo.html
-// @has - '//pre[@class="rust item-decl"]' 'fn bar(&self);'
-// @has - '//pre[@class="rust item-decl"]' 'fn foo(&mut self) { ... }'
+// @has - '//pre[@class="rust item-decl"]' '// Required method fn bar(&self);'
+// @has - '//pre[@class="rust item-decl"]' '// Provided method fn foo(&mut self)'
 pub use inline_default_methods::Foo;
+
+// @has inline_default_methods/trait.Bar.html
+// @has - '//pre[@class="rust item-decl"]' '// Required method fn bar(&self);'
+// @has - '//pre[@class="rust item-decl"]' '// Provided methods fn foo1(&mut self)'
+// @has - '//pre[@class="rust item-decl"]' 'fn foo2(&mut self)'
+pub use inline_default_methods::Bar;
+
+// @has inline_default_methods/trait.Baz.html
+// @has - '//pre[@class="rust item-decl"]' '// Required methods fn bar1(&self);'
+// @has - '//pre[@class="rust item-decl"]' 'fn bar2(&self);'
+// @has - '//pre[@class="rust item-decl"]' '// Provided method fn foo(&mut self)'
+pub use inline_default_methods::Baz;
index 2d410a5974afa46d40bc363afd2d94a780cd5971..5a49a9d06519e87a7868d3608eef75ff7b2f2508 100644 (file)
@@ -5,7 +5,7 @@
 extern crate issue_85454;
 
 // @has foo/trait.FromResidual.html
-// @has - '//pre[@class="rust item-decl"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+// @has - '//pre[@class="rust item-decl"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { // Required method 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 item-decl"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+    // @has - '//pre[@class="rust item-decl"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { // Required method fn from_residual(residual: R) -> Self; }'
     pub use issue_85454::*;
 }
index 11df902f3720f7d6cc9c87d72fd1163b3bacb2b8..858bc142f66e136ae65a8c9de67afc8d8a26e4c7 100644 (file)
@@ -1,8 +1,8 @@
 <pre class="rust item-decl"><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>;
+    type <a href="#associatedtype.Item" class="associatedtype">Item</a>&lt;'a&gt;<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span class="where">where 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>,
-    { ... }
-<span class="item-spacer" />    fn <a href="#method.lines" class="fn">lines</a>(self) -&gt; <a class="struct" href="{{channel}}/std/io/struct.Lines.html" title="struct std::io::Lines">Lines</a>&lt;Self&gt;<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>,
-    { ... }
+    // Provided methods
+    fn <a href="#method.func" class="fn">func</a>(self)<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
+<span class="item-spacer" />    fn <a href="#method.lines" class="fn">lines</a>(self) -&gt; <a class="struct" href="{{channel}}/std/io/struct.Lines.html" title="struct std::io::Lines">Lines</a>&lt;Self&gt;<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
+<span class="item-spacer" />    fn <a href="#method.merge" class="fn">merge</a>&lt;T&gt;(self, a: T)<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;T: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
 }</code></pre>
\ No newline at end of file
index 4c34c7e51d93793338ecfa1c6ce6d272fe45d27a..af3239b69470c3b24e1c562c8b26a5f7e5accf14 100644 (file)
@@ -41,6 +41,12 @@ fn lines(self) -> Lines<Self>
     where
         Self: Sized,
     { todo!() }
+
+    fn merge<T>(self, a: T)
+    where
+        Self: Sized,
+        T: Sized,
+    { todo!() }
 }
 
 // @has foo/struct.Echo.html '//*[@class="impl"]//h3[@class="code-header"]' \
index 7bc9b780197bb58467800803801a7e5d727dee6e..065ce757de1abadba4e9a9187a9cfdfee33b61de 100644 (file)
@@ -1,4 +1,4 @@
-<pre class="rust item-decl"><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; {
+<pre class="rust item-decl"><code>pub enum Cow2&lt;'a, B: ?<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>
\ No newline at end of file
index d872d516c09438c91107b43db2270e3b24867366..c647e8d71218edd764f2f2b7af317431777a14b2 100644 (file)
@@ -1,4 +1,4 @@
-<pre class="rust item-decl"><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; {
+<pre class="rust item-decl"><code>pub struct Struct2&lt;'a, B: ?<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>
\ No newline at end of file
index bc3653de52d165d53fb8bd3af0730ca4b70c1fd8..8a78e82dc71dca19394f518048d88da1eaffedb0 100644 (file)
@@ -1,6 +1,7 @@
 <pre class="rust item-decl"><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>;
 
+    // Required methods
     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>;
 <span class="item-spacer" />    fn <a href="#tymethod.whatever" class="fn">whatever</a>(&amp;self) -&gt; T;
 }</code></pre>
\ No newline at end of file
index eda4ca72acc1805ad6fda74dbcdcedfb62b26c2d..e6fafde1effe3cc91c9155e8e568013139ac51a7 100644 (file)
@@ -1,6 +1,7 @@
 <pre class="rust item-decl"><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>;
 
+    // Required methods
     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>;
 <span class="item-spacer" />    fn <a href="#tymethod.whatever" class="fn">whatever</a>(&amp;self) -&gt; T;
 }</code></pre>
\ No newline at end of file
index fc78e9b6039b0f2c7a32917ddd8a3461eae4056d..66ad30c92001f520aee5d7a561f24e008c4b5988 100644 (file)
@@ -1,3 +1,3 @@
-<pre class="rust item-decl"><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; {
+<pre class="rust item-decl"><code>pub union Union2&lt;'a, B: ?<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>
\ No newline at end of file
index a65f84ae58eadd479dffcd1d22aac7e643993330..2281d9419b461e03853b2b3b03e348501cb1271e 100644 (file)
@@ -16,8 +16,8 @@ LL |     for<'b> <Self as UnsafeCopy<'b, T>>::Item: std::ops::Deref<Target = T>,
    |                                                                ^^^^^^^^^^ required by this bound in `UnsafeCopy`
 help: consider further restricting this bound
    |
-LL | impl<T: Copy + std::ops::Deref + Deref<Target = T>> UnsafeCopy<'_, T> for T {
-   |                                +++++++++++++++++++
+LL | impl<T: Copy + std::ops::Deref<Target = T>> UnsafeCopy<'_, T> for T {
+   |                               ++++++++++++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.rs b/tests/ui/async-await/future-sizes/async-awaiting-fut.rs
new file mode 100644 (file)
index 0000000..1816d84
--- /dev/null
@@ -0,0 +1,24 @@
+// compile-flags: -Z print-type-sizes --crate-type lib
+// edition:2021
+// build-pass
+// ignore-pass
+
+async fn wait() {}
+
+async fn big_fut(arg: [u8; 1024]) {}
+
+async fn calls_fut(fut: impl std::future::Future<Output = ()>) {
+    loop {
+        wait().await;
+        if true {
+            return fut.await;
+        } else {
+            wait().await;
+        }
+    }
+}
+
+pub async fn test() {
+    let fut = big_fut([0u8; 1024]);
+    calls_fut(fut).await;
+}
diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
new file mode 100644 (file)
index 0000000..eaf3e4b
--- /dev/null
@@ -0,0 +1,72 @@
+print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:21:21: 24:2]`: 3078 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 0 bytes
+print-type-size     variant `Suspend0`: 3077 bytes
+print-type-size         local `.__awaitee`: 3077 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Returned`: 0 bytes
+print-type-size     variant `Panicked`: 0 bytes
+print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]`: 3077 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 2051 bytes
+print-type-size         padding: 1026 bytes
+print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size     variant `Suspend0`: 2052 bytes
+print-type-size         local `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         local `..generator_field4`: 1 bytes
+print-type-size         padding: 1 bytes
+print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size         local `.__awaitee`: 1 bytes
+print-type-size     variant `Suspend1`: 3076 bytes
+print-type-size         padding: 1024 bytes
+print-type-size         local `..generator_field4`: 1 bytes, alignment: 1 bytes
+print-type-size         padding: 1 bytes
+print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size         local `.__awaitee`: 1025 bytes
+print-type-size     variant `Suspend2`: 2052 bytes
+print-type-size         local `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         local `..generator_field4`: 1 bytes
+print-type-size         padding: 1 bytes
+print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size         local `.__awaitee`: 1 bytes
+print-type-size     variant `Returned`: 2051 bytes
+print-type-size         padding: 1026 bytes
+print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size     variant `Panicked`: 2051 bytes
+print-type-size         padding: 1026 bytes
+print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]>`: 3077 bytes, alignment: 1 bytes
+print-type-size     field `.value`: 3077 bytes
+print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]>`: 3077 bytes, alignment: 1 bytes
+print-type-size     variant `MaybeUninit`: 3077 bytes
+print-type-size         field `.uninit`: 0 bytes
+print-type-size         field `.value`: 3077 bytes
+print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]`: 1025 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 1024 bytes
+print-type-size         upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Returned`: 1024 bytes
+print-type-size         upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Panicked`: 1024 bytes
+print-type-size         upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]>`: 1025 bytes, alignment: 1 bytes
+print-type-size     field `.value`: 1025 bytes
+print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]>`: 1025 bytes, alignment: 1 bytes
+print-type-size     variant `MaybeUninit`: 1025 bytes
+print-type-size         field `.uninit`: 0 bytes
+print-type-size         field `.value`: 1025 bytes
+print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19]`: 1 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 0 bytes
+print-type-size     variant `Returned`: 0 bytes
+print-type-size     variant `Panicked`: 0 bytes
+print-type-size type: `std::mem::ManuallyDrop<bool>`: 1 bytes, alignment: 1 bytes
+print-type-size     field `.value`: 1 bytes
+print-type-size type: `std::mem::MaybeUninit<bool>`: 1 bytes, alignment: 1 bytes
+print-type-size     variant `MaybeUninit`: 1 bytes
+print-type-size         field `.uninit`: 0 bytes
+print-type-size         field `.value`: 1 bytes
+print-type-size type: `std::task::Poll<()>`: 1 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Ready`: 0 bytes
+print-type-size         field `.0`: 0 bytes
+print-type-size     variant `Pending`: 0 bytes
index c206d793170754dbcb6f7f23aaac6f9aa103ae5b..91db4b1531f541177ba1944d798f9d68b9fc24e0 100644 (file)
@@ -1,17 +1,17 @@
 print-type-size type: `[async fn body@$DIR/large-arg.rs:6:21: 8:2]`: 3076 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 0 bytes
 print-type-size     variant `Suspend0`: 3075 bytes
 print-type-size         local `.__awaitee`: 3075 bytes, offset: 0 bytes, alignment: 1 bytes
-print-type-size     variant `Unresumed`: 0 bytes
 print-type-size     variant `Returned`: 0 bytes
 print-type-size     variant `Panicked`: 0 bytes
 print-type-size type: `[async fn body@$DIR/large-arg.rs:10:30: 12:2]`: 3075 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 1024 bytes
+print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Suspend0`: 3074 bytes
 print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size         local `.__awaitee`: 2050 bytes
-print-type-size     variant `Unresumed`: 1024 bytes
-print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Returned`: 1024 bytes
 print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Panicked`: 1024 bytes
@@ -24,11 +24,11 @@ print-type-size         field `.uninit`: 0 bytes
 print-type-size         field `.value`: 3075 bytes
 print-type-size type: `[async fn body@$DIR/large-arg.rs:13:26: 15:2]`: 2050 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 1024 bytes
+print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Suspend0`: 2049 bytes
 print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size         local `.__awaitee`: 1025 bytes
-print-type-size     variant `Unresumed`: 1024 bytes
-print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Returned`: 1024 bytes
 print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Panicked`: 1024 bytes
index ce9f7aa050a0aca647a80a16cfc7471afa4784f4..dd0817ff2331368ac12daa488cafed47f33477ad 100644 (file)
@@ -1,11 +1,13 @@
 error[E0594]: cannot assign to `**t1`, which is behind a `&` reference
   --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:9:5
    |
-LL |     let t1 = t0;
-   |         -- consider changing this binding's type to be: `&mut &mut isize`
-LL |     let p: &isize = &**t0;
 LL |     **t1 = 22;
    |     ^^^^^^^^^ `t1` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider specifying this binding's type
+   |
+LL |     let t1: &mut &mut isize = t0;
+   |           +++++++++++++++++
 
 error[E0502]: cannot borrow `**t0` as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:14:21
index 1598cd5d3c86fa98c005b47f2f725775a809d0f6..76e0b517354168c32ec4b4462bf417e948c9c6f9 100644 (file)
@@ -1,7 +1,7 @@
 fn main() {
     let mut test = Vec::new();
     let rofl: &Vec<Vec<i32>> = &mut test;
-    //~^ NOTE consider changing this binding's type to be
+    //~^ HELP consider changing this binding's type
     rofl.push(Vec::new());
     //~^ ERROR cannot borrow `*rofl` as mutable, as it is behind a `&` reference
     //~| NOTE `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable
@@ -15,14 +15,14 @@ fn main() {
 
     #[rustfmt::skip]
     let x: &usize = &mut{0};
-    //~^ NOTE consider changing this binding's type to be
+    //~^ HELP consider changing this binding's type
     *x = 1;
     //~^ ERROR cannot assign to `*x`, which is behind a `&` reference
     //~| NOTE `x` is a `&` reference, so the data it refers to cannot be written
 
     #[rustfmt::skip]
     let y: &usize = &mut(0);
-    //~^ NOTE consider changing this binding's type to be
+    //~^ HELP consider changing this binding's type
     *y = 1;
     //~^ ERROR cannot assign to `*y`, which is behind a `&` reference
     //~| NOTE `y` is a `&` reference, so the data it refers to cannot be written
index 7da7dba68ab7aaf537a8a24ff100797e264f3f5c..b4bb128cbb420ffc881ecf1cec67f3ec5366f8b4 100644 (file)
@@ -1,11 +1,13 @@
 error[E0596]: cannot borrow `*rofl` as mutable, as it is behind a `&` reference
   --> $DIR/issue-85765.rs:5:5
    |
-LL |     let rofl: &Vec<Vec<i32>> = &mut test;
-   |         ---- consider changing this binding's type to be: `&mut Vec<Vec<i32>>`
-LL |
 LL |     rofl.push(Vec::new());
    |     ^^^^^^^^^^^^^^^^^^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this binding's type
+   |
+LL |     let rofl: &mut Vec<Vec<i32>> = &mut test;
+   |               ~~~~~~~~~~~~~~~~~~
 
 error[E0594]: cannot assign to `*r`, which is behind a `&` reference
   --> $DIR/issue-85765.rs:12:5
@@ -21,20 +23,24 @@ LL |     let r = &mut mutvar;
 error[E0594]: cannot assign to `*x`, which is behind a `&` reference
   --> $DIR/issue-85765.rs:19:5
    |
-LL |     let x: &usize = &mut{0};
-   |         - consider changing this binding's type to be: `&mut usize`
-LL |
 LL |     *x = 1;
    |     ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this binding's type
+   |
+LL |     let x: &mut usize = &mut{0};
+   |            ~~~~~~~~~~
 
 error[E0594]: cannot assign to `*y`, which is behind a `&` reference
   --> $DIR/issue-85765.rs:26:5
    |
-LL |     let y: &usize = &mut(0);
-   |         - consider changing this binding's type to be: `&mut usize`
-LL |
 LL |     *y = 1;
    |     ^^^^^^ `y` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this binding's type
+   |
+LL |     let y: &mut usize = &mut(0);
+   |            ~~~~~~~~~~
 
 error: aborting due to 4 previous errors
 
index 67407c1eae3cfe2bf2144e0e97609146d26de3b2..e062a253767ded6ab491ae70d47ed53eb8fd10e4 100644 (file)
@@ -9,7 +9,7 @@ fn get_inner_ref(&self) -> &Vec<usize> {
 fn main() {
     let client = TestClient;
     let inner = client.get_inner_ref();
-    //~^ NOTE consider changing this binding's type to be
+    //~^ HELP consider specifying this binding's type
     inner.clear();
     //~^ ERROR cannot borrow `*inner` as mutable, as it is behind a `&` reference [E0596]
     //~| NOTE `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable
index 12d8d27c5f0264906276f2753ff25ce4260e8d4e..6653d497873e79d058a20ac347d94d93d7520ea5 100644 (file)
@@ -1,11 +1,13 @@
 error[E0596]: cannot borrow `*inner` as mutable, as it is behind a `&` reference
   --> $DIR/issue-91206.rs:13:5
    |
-LL |     let inner = client.get_inner_ref();
-   |         ----- consider changing this binding's type to be: `&mut Vec<usize>`
-LL |
 LL |     inner.clear();
    |     ^^^^^^^^^^^^^ `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider specifying this binding's type
+   |
+LL |     let inner: &mut Vec<usize> = client.get_inner_ref();
+   |              +++++++++++++++++
 
 error: aborting due to previous error
 
index 62b1183e71b4beb03ce8fa9de7fc83b69533cbd5..ea4f9abb87d9adeab8fafe633bc6a09591ee8197 100644 (file)
@@ -1,10 +1,13 @@
 error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
   --> $DIR/issue-92015.rs:6:5
    |
-LL |     let foo = Some(&0).unwrap();
-   |         --- consider changing this binding's type to be: `&mut i32`
 LL |     *foo = 1;
    |     ^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider specifying this binding's type
+   |
+LL |     let foo: &mut i32 = Some(&0).unwrap();
+   |            ++++++++++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_binop_arg_tys.rs b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_binop_arg_tys.rs
new file mode 100644 (file)
index 0000000..fd52fc3
--- /dev/null
@@ -0,0 +1,18 @@
+// checks that when we relate a `Expr::Binop` we also relate the types of the
+// const arguments.
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+struct Bar<const B: bool>;
+
+const fn make_generic(_: usize, a: bool) -> bool {
+    a
+}
+
+fn foo<const N: usize>() -> Bar<{ make_generic(N, true == false) }> {
+    Bar::<{ make_generic(N, 1_u8 == 0_u8) }>
+    //~^ error: mismatched types
+    //~| error: unconstrained generic constant
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_binop_arg_tys.stderr b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_binop_arg_tys.stderr
new file mode 100644 (file)
index 0000000..ba824e8
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0308]: mismatched types
+  --> $DIR/relate_binop_arg_tys.rs:13:5
+   |
+LL |     Bar::<{ make_generic(N, 1_u8 == 0_u8) }>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ make_generic(N, true == false) }`, found `{ make_generic(N, 1_u8 == 0_u8) }`
+   |
+   = note: expected constant `{ make_generic(N, true == false) }`
+              found constant `{ make_generic(N, 1_u8 == 0_u8) }`
+
+error: unconstrained generic constant
+  --> $DIR/relate_binop_arg_tys.rs:13:11
+   |
+LL |     Bar::<{ make_generic(N, 1_u8 == 0_u8) }>
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { make_generic(N, 1_u8 == 0_u8) }]:`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_cast_arg_ty.rs b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_cast_arg_ty.rs
new file mode 100644 (file)
index 0000000..bef9d4b
--- /dev/null
@@ -0,0 +1,12 @@
+// checks that when we relate a `Expr::Cast` we also relate the type of the
+// const argument.
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn foo<const N: usize>() -> [(); (true as usize) + N] {
+    [(); (1_u8 as usize) + N]
+    //~^ error: mismatched types
+    //~| error: unconstrained generic constant
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_cast_arg_ty.stderr b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/relate_cast_arg_ty.stderr
new file mode 100644 (file)
index 0000000..d3ba870
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0308]: mismatched types
+  --> $DIR/relate_cast_arg_ty.rs:7:5
+   |
+LL |     [(); (1_u8 as usize) + N]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(true as usize) + N`, found `(1_u8 as usize) + N`
+   |
+   = note: expected constant `(true as usize) + N`
+              found constant `(1_u8 as usize) + N`
+
+error: unconstrained generic constant
+  --> $DIR/relate_cast_arg_ty.rs:7:10
+   |
+LL |     [(); (1_u8 as usize) + N]
+   |          ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); (1_u8 as usize) + N]:`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index c5c668189b9521bf375ea5bf4101891fcd61bdbf..cb0cab2444bf7a9abfe924cb96426fafa294ab3c 100644 (file)
@@ -28,24 +28,12 @@ note: erroneous constant used
 LL |     black_box((S::<i32>::FOO, S::<u32>::FOO));
    |                               ^^^^^^^^^^^^^
 
-note: erroneous constant used
-  --> $DIR/const-err-late.rs:19:31
-   |
-LL |     black_box((S::<i32>::FOO, S::<u32>::FOO));
-   |                               ^^^^^^^^^^^^^
-
 note: erroneous constant used
   --> $DIR/const-err-late.rs:19:16
    |
 LL |     black_box((S::<i32>::FOO, S::<u32>::FOO));
    |                ^^^^^^^^^^^^^
 
-note: erroneous constant used
-  --> $DIR/const-err-late.rs:19:31
-   |
-LL |     black_box((S::<i32>::FOO, S::<u32>::FOO));
-   |                               ^^^^^^^^^^^^^
-
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index 9c4ca01ff377778a6ca5ed8a89988d777e7f68da..c0c2215c04adb44d520aa84fe983587948d661a0 100644 (file)
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `B<C>: Copy` is not satisfied
-  --> $DIR/deriving-copyclone.rs:31:13
+  --> $DIR/deriving-copyclone.rs:31:26
    |
 LL |     is_copy(B { a: 1, b: C });
-   |     ------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `B<C>`
+   |     -------              ^ the trait `Copy` is not implemented for `B<C>`
    |     |
    |     required by a bound introduced by this call
    |
@@ -19,14 +19,14 @@ LL | fn is_copy<T: Copy>(_: T) {}
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider borrowing here
    |
-LL |     is_copy(&B { a: 1, b: C });
-   |             +
+LL |     is_copy(B { a: 1, b: &C });
+   |                          +
 
 error[E0277]: the trait bound `B<C>: Clone` is not satisfied
-  --> $DIR/deriving-copyclone.rs:32:14
+  --> $DIR/deriving-copyclone.rs:32:27
    |
 LL |     is_clone(B { a: 1, b: C });
-   |     -------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `B<C>`
+   |     --------              ^ the trait `Clone` is not implemented for `B<C>`
    |     |
    |     required by a bound introduced by this call
    |
@@ -43,14 +43,14 @@ LL | fn is_clone<T: Clone>(_: T) {}
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider borrowing here
    |
-LL |     is_clone(&B { a: 1, b: C });
-   |              +
+LL |     is_clone(B { a: 1, b: &C });
+   |                           +
 
 error[E0277]: the trait bound `B<D>: Copy` is not satisfied
-  --> $DIR/deriving-copyclone.rs:35:13
+  --> $DIR/deriving-copyclone.rs:35:26
    |
 LL |     is_copy(B { a: 1, b: D });
-   |     ------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `B<D>`
+   |     -------              ^ the trait `Copy` is not implemented for `B<D>`
    |     |
    |     required by a bound introduced by this call
    |
@@ -67,8 +67,8 @@ LL | fn is_copy<T: Copy>(_: T) {}
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider borrowing here
    |
-LL |     is_copy(&B { a: 1, b: D });
-   |             +
+LL |     is_copy(B { a: 1, b: &D });
+   |                          +
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/error-codes/E0523.rs b/tests/ui/error-codes/E0523.rs
new file mode 100644 (file)
index 0000000..47717fb
--- /dev/null
@@ -0,0 +1,14 @@
+// aux-build:crateresolve1-1.rs
+// aux-build:crateresolve1-2.rs
+// aux-build:crateresolve1-3.rs
+
+// normalize-stderr-test: "\.nll/" -> "/"
+// normalize-stderr-test: "\\\?\\" -> ""
+// normalize-stderr-test: "(lib)?crateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$2.somelib"
+
+// NOTE: This test is duplicated from `tests/ui/crate-loading/crateresolve1.rs`.
+
+extern crate crateresolve1;
+//~^ ERROR multiple candidates for `rlib` dependency `crateresolve1` found
+
+fn main() {}
diff --git a/tests/ui/error-codes/E0523.stderr b/tests/ui/error-codes/E0523.stderr
new file mode 100644 (file)
index 0000000..8e3eb21
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0464]: multiple candidates for `rlib` dependency `crateresolve1` found
+  --> $DIR/E0523.rs:11:1
+   |
+LL | extern crate crateresolve1;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: candidate #1: $TEST_BUILD_DIR/error-codes/E0523/auxiliary/libcrateresolve1-1.somelib
+   = note: candidate #2: $TEST_BUILD_DIR/error-codes/E0523/auxiliary/libcrateresolve1-2.somelib
+   = note: candidate #3: $TEST_BUILD_DIR/error-codes/E0523/auxiliary/libcrateresolve1-3.somelib
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0464`.
diff --git a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs
new file mode 100644 (file)
index 0000000..5134c67
--- /dev/null
@@ -0,0 +1,28 @@
+trait T1 {}
+trait T2 {}
+trait T3 {}
+trait T4 {}
+
+impl<B: T2> T1 for Wrapper<B> {}
+
+impl T2 for i32 {}
+impl T3 for i32 {}
+
+impl<A: T3> T2 for Burrito<A> {}
+
+struct Wrapper<W> {
+    value: W,
+}
+
+struct Burrito<F> {
+    filling: F,
+}
+
+fn want<V: T1>(_x: V) {}
+
+fn example<Q>(q: Q) {
+    want(Wrapper { value: Burrito { filling: q } });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+}
+
+fn main() {}
diff --git a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr
new file mode 100644 (file)
index 0000000..27b002d
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error.rs:24:46
+   |
+LL |     want(Wrapper { value: Burrito { filling: q } });
+   |     ----                                     ^ the trait `T3` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `Burrito<Q>` to implement `T2`
+  --> $DIR/blame-trait-error.rs:11:13
+   |
+LL | impl<A: T3> T2 for Burrito<A> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required for `Wrapper<Burrito<Q>>` to implement `T1`
+  --> $DIR/blame-trait-error.rs:6:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error.rs:21:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.rs b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.rs
new file mode 100644 (file)
index 0000000..2b75f43
--- /dev/null
@@ -0,0 +1,131 @@
+// This test examines the error spans reported when a generic `impl` fails.
+// For example, if a function wants an `Option<T>` where `T: Copy` but you pass `Some(vec![1, 2])`,
+// then we want to point at the `vec![1, 2]` and not the `Some( ... )` expression.
+
+trait T1 {}
+trait T2 {}
+trait T3 {}
+trait T4 {}
+
+impl T2 for i32 {}
+impl T3 for i32 {}
+
+struct Wrapper<W> {
+    value: W,
+}
+impl<B: T2> T1 for Wrapper<B> {}
+
+struct Burrito<F> {
+    spicy: bool,
+    filling: F,
+}
+impl<A: T3> T2 for Burrito<A> {}
+
+struct BurritoTuple<F>(F);
+impl<C: T3> T2 for BurritoTuple<C> {}
+
+enum BurritoKinds<G> {
+    SmallBurrito { spicy: bool, small_filling: G },
+    LargeBurrito { spicy: bool, large_filling: G },
+    MultiBurrito { first_filling: G, second_filling: G },
+}
+impl<D: T3> T2 for BurritoKinds<D> {}
+
+struct Taco<H>(bool, H);
+impl<E: T3> T2 for Taco<E> {}
+
+enum TacoKinds<H> {
+    OneTaco(bool, H),
+    TwoTacos(bool, H, H),
+}
+impl<F: T3> T2 for TacoKinds<F> {}
+
+struct GenericBurrito<Spiciness, Filling> {
+    spiciness: Spiciness,
+    filling: Filling,
+}
+impl<X, Y: T3> T2 for GenericBurrito<X, Y> {}
+struct NotSpicy;
+
+impl<A: T3, B: T3> T2 for (A, B) {}
+impl<A: T2, B: T2> T1 for (A, B) {}
+
+fn want<V: T1>(_x: V) {}
+
+// Some more-complex examples:
+type AliasBurrito<T> = GenericBurrito<T, T>;
+
+// The following example is fairly confusing. The idea is that we want to "misdirect" the location
+// of the error.
+
+struct Two<A, B> {
+    a: A,
+    b: B,
+}
+
+impl<X, Y: T1, Z> T1 for Two<Two<X, Y>, Z> {}
+
+struct DoubleWrapper<T> {
+    item: Wrapper<T>,
+}
+
+impl<T: T1> T1 for DoubleWrapper<T> {}
+
+fn example<Q>(q: Q) {
+    // In each of the following examples, we expect the error span to point at the 'q' variable,
+    // since the missing constraint is `Q: T3`.
+
+    // Verifies for struct:
+    want(Wrapper { value: Burrito { spicy: false, filling: q } });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    // Verifies for enum with named fields in variant:
+    want(Wrapper { value: BurritoKinds::SmallBurrito { spicy: true, small_filling: q } });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    // Verifies for tuple struct:
+    want(Wrapper { value: Taco(false, q) });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    // Verifies for tuple enum variant:
+    want(Wrapper { value: TacoKinds::OneTaco(false, q) });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    // Verifies for generic type with multiple parameters:
+    want(Wrapper { value: GenericBurrito { spiciness: NotSpicy, filling: q } });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    // Verifies for tuple:
+    want((3, q));
+    //~^ ERROR the trait bound `Q: T2` is not satisfied [E0277]
+
+    // Verifies for nested tuple:
+    want(Wrapper { value: (3, q) });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    // Verifies for nested tuple:
+    want(((3, q), 5));
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    want(DoubleWrapper { item: Wrapper { value: q } });
+    //~^ ERROR the trait bound `Q: T1` is not satisfied [E0277]
+
+    want(DoubleWrapper { item: Wrapper { value: DoubleWrapper { item: Wrapper { value: q } } } });
+    //~^ ERROR the trait bound `Q: T1` is not satisfied [E0277]
+
+    // Verifies for type alias to struct:
+    want(Wrapper { value: AliasBurrito { spiciness: q, filling: q } });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    want(Two { a: Two { a: (), b: q }, b: () });
+    //~^ ERROR the trait bound `Q: T1` is not satisfied [E0277]
+
+    // We *should* blame the 'q'.
+    // FIXME: Right now, the wrong field is blamed.
+    want(
+        Two { a: Two { a: (), b: Two { a: Two { a: (), b: q }, b: () } }, b: () },
+        //~^ ERROR the trait bound `Q: T1` is not satisfied [E0277]
+    );
+}
+
+fn main() {}
diff --git a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr
new file mode 100644 (file)
index 0000000..5f87c67
--- /dev/null
@@ -0,0 +1,380 @@
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:79:60
+   |
+LL |     want(Wrapper { value: Burrito { spicy: false, filling: q } });
+   |     ---- required by a bound introduced by this call       ^ the trait `T3` is not implemented for `Q`
+   |
+note: required for `Burrito<Q>` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:22:13
+   |
+LL | impl<A: T3> T2 for Burrito<A> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required for `Wrapper<Burrito<Q>>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:83:84
+   |
+LL |     want(Wrapper { value: BurritoKinds::SmallBurrito { spicy: true, small_filling: q } });
+   |     ---- required by a bound introduced by this call                               ^ the trait `T3` is not implemented for `Q`
+   |
+note: required for `BurritoKinds<Q>` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:32:13
+   |
+LL | impl<D: T3> T2 for BurritoKinds<D> {}
+   |         --  ^^     ^^^^^^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required for `Wrapper<BurritoKinds<Q>>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:87:39
+   |
+LL |     want(Wrapper { value: Taco(false, q) });
+   |     ----                              ^ the trait `T3` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `Taco<Q>` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:35:13
+   |
+LL | impl<E: T3> T2 for Taco<E> {}
+   |         --  ^^     ^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required for `Wrapper<Taco<Q>>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:91:27
+   |
+LL |     want(Wrapper { value: TacoKinds::OneTaco(false, q) });
+   |     ----                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `T3` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `TacoKinds<Q>` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:41:13
+   |
+LL | impl<F: T3> T2 for TacoKinds<F> {}
+   |         --  ^^     ^^^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required for `Wrapper<TacoKinds<Q>>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:95:74
+   |
+LL |     want(Wrapper { value: GenericBurrito { spiciness: NotSpicy, filling: q } });
+   |     ---- required by a bound introduced by this call                     ^ the trait `T3` is not implemented for `Q`
+   |
+note: required for `GenericBurrito<NotSpicy, Q>` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:47:16
+   |
+LL | impl<X, Y: T3> T2 for GenericBurrito<X, Y> {}
+   |            --  ^^     ^^^^^^^^^^^^^^^^^^^^
+   |            |
+   |            unsatisfied trait bound introduced here
+note: required for `Wrapper<GenericBurrito<NotSpicy, Q>>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T2` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:99:14
+   |
+LL |     want((3, q));
+   |     ----     ^ the trait `T2` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `(i32, Q)` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:51:20
+   |
+LL | impl<A: T2, B: T2> T1 for (A, B) {}
+   |                --  ^^     ^^^^^^
+   |                |
+   |                unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T2>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:103:31
+   |
+LL |     want(Wrapper { value: (3, q) });
+   |     ----                      ^ the trait `T3` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `(i32, Q)` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:50:20
+   |
+LL | impl<A: T3, B: T3> T2 for (A, B) {}
+   |                --  ^^     ^^^^^^
+   |                |
+   |                unsatisfied trait bound introduced here
+note: required for `Wrapper<(i32, Q)>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:107:15
+   |
+LL |     want(((3, q), 5));
+   |     ----      ^ the trait `T3` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `(i32, Q)` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:50:20
+   |
+LL | impl<A: T3, B: T3> T2 for (A, B) {}
+   |                --  ^^     ^^^^^^
+   |                |
+   |                unsatisfied trait bound introduced here
+note: required for `((i32, Q), i32)` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:51:20
+   |
+LL | impl<A: T2, B: T2> T1 for (A, B) {}
+   |         --         ^^     ^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T1` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:110:49
+   |
+LL |     want(DoubleWrapper { item: Wrapper { value: q } });
+   |     ----                                        ^ the trait `T1` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `DoubleWrapper<Q>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:72:13
+   |
+LL | impl<T: T1> T1 for DoubleWrapper<T> {}
+   |         --  ^^     ^^^^^^^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T1>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T1` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:113:88
+   |
+LL |     want(DoubleWrapper { item: Wrapper { value: DoubleWrapper { item: Wrapper { value: q } } } });
+   |     ---- required by a bound introduced by this call                                   ^ the trait `T1` is not implemented for `Q`
+   |
+note: required for `DoubleWrapper<Q>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:72:13
+   |
+LL | impl<T: T1> T1 for DoubleWrapper<T> {}
+   |         --  ^^     ^^^^^^^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: 1 redundant requirement hidden
+   = note: required for `DoubleWrapper<DoubleWrapper<Q>>` to implement `T1`
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T1>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:117:27
+   |
+LL |     want(Wrapper { value: AliasBurrito { spiciness: q, filling: q } });
+   |     ----                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `T3` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `GenericBurrito<Q, Q>` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:47:16
+   |
+LL | impl<X, Y: T3> T2 for GenericBurrito<X, Y> {}
+   |            --  ^^     ^^^^^^^^^^^^^^^^^^^^
+   |            |
+   |            unsatisfied trait bound introduced here
+note: required for `Wrapper<GenericBurrito<Q, Q>>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T1` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:120:35
+   |
+LL |     want(Two { a: Two { a: (), b: q }, b: () });
+   |     ----                          ^ the trait `T1` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `Two<Two<(), Q>, ()>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:66:19
+   |
+LL | impl<X, Y: T1, Z> T1 for Two<Two<X, Y>, Z> {}
+   |            --     ^^     ^^^^^^^^^^^^^^^^^
+   |            |
+   |            unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T1>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T1` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:126:59
+   |
+LL |     want(
+   |     ---- required by a bound introduced by this call
+LL |         Two { a: Two { a: (), b: Two { a: Two { a: (), b: q }, b: () } }, b: () },
+   |                                                           ^ the trait `T1` is not implemented for `Q`
+   |
+note: required for `Two<Two<(), Q>, ()>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:66:19
+   |
+LL | impl<X, Y: T1, Z> T1 for Two<Two<X, Y>, Z> {}
+   |            --     ^^     ^^^^^^^^^^^^^^^^^
+   |            |
+   |            unsatisfied trait bound introduced here
+   = note: 1 redundant requirement hidden
+   = note: required for `Two<Two<(), Two<Two<(), Q>, ()>>, ()>` to implement `T1`
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T1>(q: Q) {
+   |             ++++
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index e8770aedfa1c7940318acbd9200731fa2a91b362..f0212e985a92cdd95e411b4fcc777ff8a6e859dc 100644 (file)
@@ -15,8 +15,8 @@ LL |     type Item<'a>: std::ops::Deref<Target = T>;
    |                                    ^^^^^^^^^^ required by this bound in `UnsafeCopy::Item`
 help: consider further restricting this bound
    |
-LL | impl<T: Copy + std::ops::Deref + Deref<Target = T>> UnsafeCopy<T> for T {
-   |                                +++++++++++++++++++
+LL | impl<T: Copy + std::ops::Deref<Target = T>> UnsafeCopy<T> for T {
+   |                               ++++++++++++
 
 error: aborting due to previous error
 
index ee758f19ec105345066f5437ce2e17aaf125cc63..054adbffbeafb66317e041b162ed5520584b4c3a 100644 (file)
@@ -4,7 +4,7 @@ use std::ops::Add;
 
 struct A<B>(B);
 
-impl<B> Add for A<B> where B: Add + Add<Output = B> {
+impl<B> Add for A<B> where B: Add<Output = B> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
@@ -14,7 +14,7 @@ impl<B> Add for A<B> where B: Add + Add<Output = B> {
 
 struct C<B>(B);
 
-impl<B: Add + Add<Output = B>> Add for C<B> {
+impl<B: Add<Output = B>> Add for C<B> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
@@ -34,7 +34,7 @@ impl<B: std::ops::Add<Output = B>> Add for D<B> {
 
 struct E<B>(B);
 
-impl<B: Add + Add<Output = B>> Add for E<B> where B: Add<Output = B> {
+impl<B: Add<Output = B>> Add for E<B> where B: Add<Output = B> {
     //~^ ERROR equality constraints are not yet supported in `where` clauses
     type Output = Self;
 
index 9f669b9a5214b1694bb3c42331ca48480826526f..535edec575a7d715f1e061740db25993337a3ac4 100644 (file)
@@ -37,8 +37,8 @@ LL | struct A<B>(B);
    |        ^
 help: consider further restricting this bound
    |
-LL | impl<B> Add for A<B> where B: Add + Add<Output = B> {
-   |                                   +++++++++++++++++
+LL | impl<B> Add for A<B> where B: Add<Output = B> {
+   |                                  ++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/missing-bounds.rs:21:14
@@ -60,8 +60,8 @@ LL | struct C<B>(B);
    |        ^
 help: consider further restricting this bound
    |
-LL | impl<B: Add + Add<Output = B>> Add for C<B> {
-   |             +++++++++++++++++
+LL | impl<B: Add<Output = B>> Add for C<B> {
+   |            ++++++++++++
 
 error[E0369]: cannot add `B` to `B`
   --> $DIR/missing-bounds.rs:31:21
@@ -96,8 +96,8 @@ LL | struct E<B>(B);
    |        ^
 help: consider further restricting this bound
    |
-LL | impl<B: Add + Add<Output = B>> Add for E<B> where <B as Add>::Output = B {
-   |             +++++++++++++++++
+LL | impl<B: Add<Output = B>> Add for E<B> where <B as Add>::Output = B {
+   |            ++++++++++++
 
 error: aborting due to 5 previous errors
 
index 797c1085d517b1b44b9159f6252a29399d92c328..84e09afac0a2dca67beff200753c983da299d3b7 100644 (file)
@@ -5,6 +5,7 @@ fn main() {
     *foo = 32;
     //~^ ERROR cannot assign to `*foo`, which is behind a `&` reference
     let bar = foo;
+    //~^ HELP consider specifying this binding's type
     *bar = 64;
     //~^ ERROR cannot assign to `*bar`, which is behind a `&` reference
 }
index c4e61e719539280b1bc96b9e87fae6ae4c180ffd..94e5c9f1b832a6e019e1c8273ba76f4c7c448c45 100644 (file)
@@ -10,12 +10,15 @@ LL |     let foo = &mut 16;
    |               ~~~~~~~
 
 error[E0594]: cannot assign to `*bar`, which is behind a `&` reference
-  --> $DIR/issue-51515.rs:8:5
+  --> $DIR/issue-51515.rs:9:5
    |
-LL |     let bar = foo;
-   |         --- consider changing this binding's type to be: `&mut i32`
 LL |     *bar = 64;
    |     ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider specifying this binding's type
+   |
+LL |     let bar: &mut i32 = foo;
+   |            ++++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-92741.fixed b/tests/ui/issues/issue-92741.fixed
new file mode 100644 (file)
index 0000000..d07aeb6
--- /dev/null
@@ -0,0 +1,13 @@
+// run-rustfix
+fn main() {}
+fn _foo() -> bool {
+    if true { true } else { false }
+}
+
+fn _bar() -> bool {
+    if true { true } else { false }
+}
+
+fn _baz() -> bool {
+    if true { true } else { false }
+}
diff --git a/tests/ui/issues/issue-92741.rs b/tests/ui/issues/issue-92741.rs
new file mode 100644 (file)
index 0000000..413d5bf
--- /dev/null
@@ -0,0 +1,17 @@
+// run-rustfix
+fn main() {}
+fn _foo() -> bool {
+    &  //~ ERROR 4:5: 6:36: mismatched types [E0308]
+    mut
+    if true { true } else { false }
+}
+
+fn _bar() -> bool {
+    &  //~ ERROR 10:5: 11:40: mismatched types [E0308]
+    mut if true { true } else { false }
+}
+
+fn _baz() -> bool {
+    & mut //~ ERROR 15:5: 16:36: mismatched types [E0308]
+    if true { true } else { false }
+}
diff --git a/tests/ui/issues/issue-92741.stderr b/tests/ui/issues/issue-92741.stderr
new file mode 100644 (file)
index 0000000..49315e7
--- /dev/null
@@ -0,0 +1,49 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-92741.rs:4:5
+   |
+LL |   fn _foo() -> bool {
+   |                ---- expected `bool` because of return type
+LL | /     &
+LL | |     mut
+LL | |     if true { true } else { false }
+   | |___________________________________^ expected `bool`, found `&mut bool`
+   |
+help: consider removing the borrow
+   |
+LL -     &
+LL -     mut
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-92741.rs:10:5
+   |
+LL |   fn _bar() -> bool {
+   |                ---- expected `bool` because of return type
+LL | /     &
+LL | |     mut if true { true } else { false }
+   | |_______________________________________^ expected `bool`, found `&mut bool`
+   |
+help: consider removing the borrow
+   |
+LL -     &
+LL -     mut if true { true } else { false }
+LL +     if true { true } else { false }
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-92741.rs:15:5
+   |
+LL |   fn _baz() -> bool {
+   |                ---- expected `bool` because of return type
+LL | /     & mut
+LL | |     if true { true } else { false }
+   | |___________________________________^ expected `bool`, found `&mut bool`
+   |
+help: consider removing the borrow
+   |
+LL -     & mut
+   |
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lifetimes/issue-107492-default-value-for-lifetime.rs b/tests/ui/lifetimes/issue-107492-default-value-for-lifetime.rs
new file mode 100644 (file)
index 0000000..f129035
--- /dev/null
@@ -0,0 +1,6 @@
+pub struct DefaultLifetime<'a, 'b = 'static> {
+                                   //~^ ERROR unexpected default lifetime parameter
+    _marker: std::marker::PhantomData<&'a &'b ()>,
+}
+
+fn main(){}
diff --git a/tests/ui/lifetimes/issue-107492-default-value-for-lifetime.stderr b/tests/ui/lifetimes/issue-107492-default-value-for-lifetime.stderr
new file mode 100644 (file)
index 0000000..c235c31
--- /dev/null
@@ -0,0 +1,8 @@
+error: unexpected default lifetime parameter
+  --> $DIR/issue-107492-default-value-for-lifetime.rs:1:35
+   |
+LL | pub struct DefaultLifetime<'a, 'b = 'static> {
+   |                                   ^^^^^^^^^ lifetime parameters cannot have default values
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/unused/issue-103320-must-use-ops.rs b/tests/ui/lint/unused/issue-103320-must-use-ops.rs
new file mode 100644 (file)
index 0000000..597d312
--- /dev/null
@@ -0,0 +1,27 @@
+// check-pass
+
+#![warn(unused_must_use)]
+#![feature(never_type)]
+
+use std::ops::Add;
+use std::ops::Sub;
+use std::ops::Mul;
+use std::ops::Div;
+use std::ops::Rem;
+
+fn main() {
+    let x = 2_u32;
+    (x.add(4), x.sub(4), x.mul(4), x.div(4), x.rem(4));
+
+    x.add(4); //~ WARN unused return value of `add` that must be used
+
+    x.sub(4); //~ WARN unused return value of `sub` that must be used
+
+    x.mul(4); //~ WARN unused return value of `mul` that must be used
+
+    x.div(4); //~ WARN unused return value of `div` that must be used
+
+    x.rem(4); //~ WARN unused return value of `rem` that must be used
+
+    println!("{}", x);
+}
diff --git a/tests/ui/lint/unused/issue-103320-must-use-ops.stderr b/tests/ui/lint/unused/issue-103320-must-use-ops.stderr
new file mode 100644 (file)
index 0000000..57439ec
--- /dev/null
@@ -0,0 +1,67 @@
+warning: unused return value of `add` that must be used
+  --> $DIR/issue-103320-must-use-ops.rs:16:5
+   |
+LL |     x.add(4);
+   |     ^^^^^^^^
+   |
+   = note: this returns the result of the operation, without modifying the original
+note: the lint level is defined here
+  --> $DIR/issue-103320-must-use-ops.rs:3:9
+   |
+LL | #![warn(unused_must_use)]
+   |         ^^^^^^^^^^^^^^^
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = x.add(4);
+   |     +++++++
+
+warning: unused return value of `sub` that must be used
+  --> $DIR/issue-103320-must-use-ops.rs:18:5
+   |
+LL |     x.sub(4);
+   |     ^^^^^^^^
+   |
+   = note: this returns the result of the operation, without modifying the original
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = x.sub(4);
+   |     +++++++
+
+warning: unused return value of `mul` that must be used
+  --> $DIR/issue-103320-must-use-ops.rs:20:5
+   |
+LL |     x.mul(4);
+   |     ^^^^^^^^
+   |
+   = note: this returns the result of the operation, without modifying the original
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = x.mul(4);
+   |     +++++++
+
+warning: unused return value of `div` that must be used
+  --> $DIR/issue-103320-must-use-ops.rs:22:5
+   |
+LL |     x.div(4);
+   |     ^^^^^^^^
+   |
+   = note: this returns the result of the operation, without modifying the original
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = x.div(4);
+   |     +++++++
+
+warning: unused return value of `rem` that must be used
+  --> $DIR/issue-103320-must-use-ops.rs:24:5
+   |
+LL |     x.rem(4);
+   |     ^^^^^^^^
+   |
+   = note: this returns the result of the operation, without modifying the original
+help: use `let _ = ...` to ignore the resulting value
+   |
+LL |     let _ = x.rem(4);
+   |     +++++++
+
+warning: 5 warnings emitted
+
diff --git a/tests/ui/malformed/issue-107423-unused-delim-only-one-no-pair.rs b/tests/ui/malformed/issue-107423-unused-delim-only-one-no-pair.rs
new file mode 100644 (file)
index 0000000..4003ee3
--- /dev/null
@@ -0,0 +1,7 @@
+// check that we don't generate a span that points beyond EOF
+
+// error-pattern: unclosed delimiter
+// error-pattern: unclosed delimiter
+// error-pattern: unclosed delimiter
+
+fn a(){{{
diff --git a/tests/ui/malformed/issue-107423-unused-delim-only-one-no-pair.stderr b/tests/ui/malformed/issue-107423-unused-delim-only-one-no-pair.stderr
new file mode 100644 (file)
index 0000000..0479035
--- /dev/null
@@ -0,0 +1,32 @@
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-107423-unused-delim-only-one-no-pair.rs:7:11
+   |
+LL | fn a(){{{
+   |       --- ^
+   |       |||
+   |       ||unclosed delimiter
+   |       |unclosed delimiter
+   |       unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-107423-unused-delim-only-one-no-pair.rs:7:11
+   |
+LL | fn a(){{{
+   |       --- ^
+   |       |||
+   |       ||unclosed delimiter
+   |       |unclosed delimiter
+   |       unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-107423-unused-delim-only-one-no-pair.rs:7:11
+   |
+LL | fn a(){{{
+   |       --- ^
+   |       |||
+   |       ||unclosed delimiter
+   |       |unclosed delimiter
+   |       unclosed delimiter
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/mir/issue-107678-projection-with-lifetime.rs b/tests/ui/mir/issue-107678-projection-with-lifetime.rs
new file mode 100644 (file)
index 0000000..14a4568
--- /dev/null
@@ -0,0 +1,20 @@
+// build-pass
+
+#![crate_type = "lib"]
+
+pub trait StreamOnce {
+    type Error;
+}
+
+pub trait ResetStream: StreamOnce {
+    fn reset(&mut self) -> Result<(), Self::Error>;
+}
+
+impl<'a> ResetStream for &'a str
+    where Self: StreamOnce
+{
+    #[inline]
+    fn reset(&mut self) -> Result<(), Self::Error> {
+        Ok(())
+    }
+}
diff --git a/tests/ui/mir/issue-107691.rs b/tests/ui/mir/issue-107691.rs
new file mode 100644 (file)
index 0000000..517a172
--- /dev/null
@@ -0,0 +1,42 @@
+// build-pass
+// compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+pub trait Archive {
+    type Archived;
+    type Resolver;
+
+    fn resolve(resolver: Self::Resolver, out: *mut Self::Archived);
+}
+
+pub type Archived<T> = <T as Archive>::Archived;
+pub type Resolver<T> = <T as Archive>::Resolver;
+
+pub struct Record<'a> {
+    _payload: &'a [u8],
+}
+
+pub struct ArchivedRecord<'a>
+where
+    &'a [u8]: Archive,
+{
+    _payload: Archived<&'a [u8]>,
+}
+
+pub struct RecordResolver<'a>
+where
+    &'a [u8]: Archive,
+{
+    _payload: Resolver<&'a [u8]>,
+}
+
+impl<'a> Archive for Record<'a>
+where
+    &'a [u8]: Archive,
+{
+    type Archived = ArchivedRecord<'a>;
+    type Resolver = RecordResolver<'a>;
+
+    fn resolve(_resolver: Self::Resolver, _out: *mut Self::Archived) {}
+}
diff --git a/tests/ui/parser/missing-expression-in-for-loop.rs b/tests/ui/parser/missing-expression-in-for-loop.rs
new file mode 100644 (file)
index 0000000..518a89a
--- /dev/null
@@ -0,0 +1,5 @@
+fn main() {
+    for i in {
+        //~^ ERROR missing expression to iterate on in `for` loop
+    }
+}
diff --git a/tests/ui/parser/missing-expression-in-for-loop.stderr b/tests/ui/parser/missing-expression-in-for-loop.stderr
new file mode 100644 (file)
index 0000000..74a7c42
--- /dev/null
@@ -0,0 +1,13 @@
+error: missing expression to iterate on in `for` loop
+  --> $DIR/missing-expression-in-for-loop.rs:2:14
+   |
+LL |     for i in {
+   |              ^
+   |
+help: try adding an expression to the `for` loop
+   |
+LL |     for i in /* expression */ {
+   |              ++++++++++++++++
+
+error: aborting due to previous error
+
index df22f5e065c8fde7c1df84225b78d65e721c107a..10af39b70074882ef906f592ac57975f4df7beba 100644 (file)
@@ -7,6 +7,6 @@ fn main() {
 enum Foo { Bar }
 fn foo(x: impl Iterator<Item = Foo>) {
     for <Foo>::Bar in x {}
-    //~^ ERROR expected one of `const`, `move`, `static`, `|`
+    //~^ ERROR expected one of `move`, `static`, `|`
     //~^^ ERROR `for<...>` binders for closures are experimental
 }
index 9ec4d2c034d0fe35da4ae7597886ddc16bd4521b..39eec80f658ad9344ab64a8091c32381806b2b81 100644 (file)
@@ -1,8 +1,8 @@
-error: expected one of `const`, `move`, `static`, `|`, or `||`, found `::`
+error: expected one of `move`, `static`, `|`, or `||`, found `::`
   --> $DIR/recover-quantified-closure.rs:9:14
    |
 LL |     for <Foo>::Bar in x {}
-   |              ^^ expected one of `const`, `move`, `static`, `|`, or `||`
+   |              ^^ expected one of `move`, `static`, `|`, or `||`
 
 error[E0658]: `for<...>` binders for closures are experimental
   --> $DIR/recover-quantified-closure.rs:2:5
index 4588c0ebd81b0c250862e941b6ee986500f7e401..8fe936efc8983ed96b21ecdb7ef781b6227cbe39 100644 (file)
@@ -1,11 +1,11 @@
 print-type-size type: `[async fn body@$DIR/async.rs:8:36: 11:2]`: 16386 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 8192 bytes
+print-type-size         upvar `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Suspend0`: 16385 bytes
 print-type-size         upvar `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size         local `.arg`: 8192 bytes
 print-type-size         local `.__awaitee`: 1 bytes
-print-type-size     variant `Unresumed`: 8192 bytes
-print-type-size         upvar `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Returned`: 8192 bytes
 print-type-size         upvar `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Panicked`: 8192 bytes
index 13d850a66902f87654273f3a61248b2ddcd4e334..7c58d6ce5ffa1e79785cd7577cbe5174c8d8f082 100644 (file)
@@ -2,9 +2,9 @@ print-type-size type: `[generator@$DIR/generator.rs:10:5: 10:14]`: 8193 bytes, a
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 8192 bytes
 print-type-size         upvar `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Suspend0`: 8192 bytes
+print-type-size         upvar `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Returned`: 8192 bytes
 print-type-size         upvar `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Panicked`: 8192 bytes
 print-type-size         upvar `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
-print-type-size     variant `Suspend0`: 8192 bytes
-print-type-size         upvar `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
index b294b2d139c3cfab9e60feb561adb5d3b65fb119..f2a11c7a33bab49c2d8f343d8fb63f610be500dc 100644 (file)
@@ -1,11 +1,11 @@
 print-type-size type: `[generator@$DIR/generator_discr_placement.rs:11:13: 11:15]`: 8 bytes, alignment: 4 bytes
 print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 0 bytes
 print-type-size     variant `Suspend0`: 7 bytes
 print-type-size         padding: 3 bytes
 print-type-size         local `.w`: 4 bytes, alignment: 4 bytes
 print-type-size     variant `Suspend1`: 7 bytes
 print-type-size         padding: 3 bytes
 print-type-size         local `.z`: 4 bytes, alignment: 4 bytes
-print-type-size     variant `Unresumed`: 0 bytes
 print-type-size     variant `Returned`: 0 bytes
 print-type-size     variant `Panicked`: 0 bytes
index dde8ad1b6b327615fe66c1c2c75a644275dd3477..64683ae3a6ebd13c175e91fb9dce51109f22c756 100644 (file)
@@ -9,9 +9,11 @@ LL |     func(&mut iter.map(|x| x + 1))
    = help: a `loop` may express intention better if this is on purpose
    = note: `#[warn(unconditional_recursion)]` on by default
 
-error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<..., ...>, ...>, ...>, ...>: Iterator`
+error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:12:24: 12:27]>: Iterator`
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`)
+   = note: required for `&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:12:24: 12:27]>` to implement `Iterator`
+   = note: 65 redundant requirements hidden
    = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<..., ...>, ...>, ...>, ...>, ...>, ...>, ...>` to implement `Iterator`
    = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type-hash.txt'
 
diff --git a/tests/ui/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs b/tests/ui/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs
new file mode 100644 (file)
index 0000000..2c99d8b
--- /dev/null
@@ -0,0 +1,10 @@
+// check-pass
+
+#![feature(const_trait_impl, const_closures)]
+#![allow(incomplete_features)]
+
+const fn test() -> impl ~const Fn() {
+    const move || {}
+}
+
+fn main() {}
diff --git a/tests/ui/suggest-null-ptr.fixed b/tests/ui/suggest-null-ptr.fixed
new file mode 100644 (file)
index 0000000..40f900c
--- /dev/null
@@ -0,0 +1,31 @@
+// run-rustfix
+
+// Suggest providing a std::ptr::null{,_mut}() to a function that takes in a raw
+// pointer if a literal 0 was provided by the user.
+
+extern "C" {
+    fn foo(ptr: *const u8);
+
+    fn foo_mut(ptr: *mut u8);
+
+    fn usize(ptr: *const usize);
+
+    fn usize_mut(ptr: *mut usize);
+}
+
+fn main() {
+    unsafe {
+        foo(std::ptr::null());
+        //~^ mismatched types [E0308]
+        //~| if you meant to create a null pointer, use `std::ptr::null()`
+        foo_mut(std::ptr::null_mut());
+        //~^ mismatched types [E0308]
+        //~| if you meant to create a null pointer, use `std::ptr::null_mut()`
+        usize(std::ptr::null());
+        //~^ mismatched types [E0308]
+        //~| if you meant to create a null pointer, use `std::ptr::null()`
+        usize_mut(std::ptr::null_mut());
+        //~^ mismatched types [E0308]
+        //~| if you meant to create a null pointer, use `std::ptr::null_mut()`
+    }
+}
diff --git a/tests/ui/suggest-null-ptr.rs b/tests/ui/suggest-null-ptr.rs
new file mode 100644 (file)
index 0000000..19b595b
--- /dev/null
@@ -0,0 +1,31 @@
+// run-rustfix
+
+// Suggest providing a std::ptr::null{,_mut}() to a function that takes in a raw
+// pointer if a literal 0 was provided by the user.
+
+extern "C" {
+    fn foo(ptr: *const u8);
+
+    fn foo_mut(ptr: *mut u8);
+
+    fn usize(ptr: *const usize);
+
+    fn usize_mut(ptr: *mut usize);
+}
+
+fn main() {
+    unsafe {
+        foo(0);
+        //~^ mismatched types [E0308]
+        //~| if you meant to create a null pointer, use `std::ptr::null()`
+        foo_mut(0);
+        //~^ mismatched types [E0308]
+        //~| if you meant to create a null pointer, use `std::ptr::null_mut()`
+        usize(0);
+        //~^ mismatched types [E0308]
+        //~| if you meant to create a null pointer, use `std::ptr::null()`
+        usize_mut(0);
+        //~^ mismatched types [E0308]
+        //~| if you meant to create a null pointer, use `std::ptr::null_mut()`
+    }
+}
diff --git a/tests/ui/suggest-null-ptr.stderr b/tests/ui/suggest-null-ptr.stderr
new file mode 100644 (file)
index 0000000..66a79d0
--- /dev/null
@@ -0,0 +1,83 @@
+error[E0308]: mismatched types
+  --> $DIR/suggest-null-ptr.rs:18:13
+   |
+LL |         foo(0);
+   |         --- ^ expected `*const u8`, found `usize`
+   |         |
+   |         arguments to this function are incorrect
+   |
+   = note: expected raw pointer `*const u8`
+                     found type `usize`
+note: function defined here
+  --> $DIR/suggest-null-ptr.rs:7:8
+   |
+LL |     fn foo(ptr: *const u8);
+   |        ^^^
+help: if you meant to create a null pointer, use `std::ptr::null()`
+   |
+LL |         foo(std::ptr::null());
+   |             ~~~~~~~~~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-null-ptr.rs:21:17
+   |
+LL |         foo_mut(0);
+   |         ------- ^ expected `*mut u8`, found `usize`
+   |         |
+   |         arguments to this function are incorrect
+   |
+   = note: expected raw pointer `*mut u8`
+                     found type `usize`
+note: function defined here
+  --> $DIR/suggest-null-ptr.rs:9:8
+   |
+LL |     fn foo_mut(ptr: *mut u8);
+   |        ^^^^^^^
+help: if you meant to create a null pointer, use `std::ptr::null_mut()`
+   |
+LL |         foo_mut(std::ptr::null_mut());
+   |                 ~~~~~~~~~~~~~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-null-ptr.rs:24:15
+   |
+LL |         usize(0);
+   |         ----- ^ expected `*const usize`, found `usize`
+   |         |
+   |         arguments to this function are incorrect
+   |
+   = note: expected raw pointer `*const usize`
+                     found type `usize`
+note: function defined here
+  --> $DIR/suggest-null-ptr.rs:11:8
+   |
+LL |     fn usize(ptr: *const usize);
+   |        ^^^^^
+help: if you meant to create a null pointer, use `std::ptr::null()`
+   |
+LL |         usize(std::ptr::null());
+   |               ~~~~~~~~~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-null-ptr.rs:27:19
+   |
+LL |         usize_mut(0);
+   |         --------- ^ expected `*mut usize`, found `usize`
+   |         |
+   |         arguments to this function are incorrect
+   |
+   = note: expected raw pointer `*mut usize`
+                     found type `usize`
+note: function defined here
+  --> $DIR/suggest-null-ptr.rs:13:8
+   |
+LL |     fn usize_mut(ptr: *mut usize);
+   |        ^^^^^^^^^
+help: if you meant to create a null pointer, use `std::ptr::null_mut()`
+   |
+LL |         usize_mut(std::ptr::null_mut());
+   |                   ~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/suggestions/restrict-existing-type-bounds.rs b/tests/ui/suggestions/restrict-existing-type-bounds.rs
new file mode 100644 (file)
index 0000000..07712ce
--- /dev/null
@@ -0,0 +1,30 @@
+pub trait TryAdd<Rhs = Self> {
+    type Error;
+    type Output;
+
+    fn try_add(self, rhs: Rhs) -> Result<Self::Output, Self::Error>;
+}
+
+impl<T: TryAdd> TryAdd for Option<T> {
+    type Error = <T as TryAdd>::Error;
+    type Output = Option<<T as TryAdd>::Output>;
+
+    fn try_add(self, rhs: Self) -> Result<Self::Output, Self::Error> {
+        Ok(self) //~ ERROR mismatched types
+    }
+}
+
+struct Other<A>(A);
+
+struct X;
+
+impl<T: TryAdd<Error = X>> TryAdd for Other<T> {
+    type Error = <T as TryAdd>::Error;
+    type Output = Other<<T as TryAdd>::Output>;
+
+    fn try_add(self, rhs: Self) -> Result<Self::Output, Self::Error> {
+        Ok(self) //~ ERROR mismatched types
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/restrict-existing-type-bounds.stderr b/tests/ui/suggestions/restrict-existing-type-bounds.stderr
new file mode 100644 (file)
index 0000000..14a244b
--- /dev/null
@@ -0,0 +1,57 @@
+error[E0308]: mismatched types
+  --> $DIR/restrict-existing-type-bounds.rs:13:12
+   |
+LL | impl<T: TryAdd> TryAdd for Option<T> {
+   |      - this type parameter
+...
+LL |         Ok(self)
+   |         -- ^^^^ expected `Option<<T as TryAdd>::Output>`, found `Option<T>`
+   |         |
+   |         arguments to this enum variant are incorrect
+   |
+   = note: expected enum `Option<<T as TryAdd>::Output>`
+              found enum `Option<T>`
+help: the type constructed contains `Option<T>` due to the type of the argument passed
+  --> $DIR/restrict-existing-type-bounds.rs:13:9
+   |
+LL |         Ok(self)
+   |         ^^^----^
+   |            |
+   |            this argument influences the type of `Ok`
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+help: consider further restricting this bound
+   |
+LL | impl<T: TryAdd<Output = T>> TryAdd for Option<T> {
+   |               ++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/restrict-existing-type-bounds.rs:26:12
+   |
+LL | impl<T: TryAdd<Error = X>> TryAdd for Other<T> {
+   |      - this type parameter
+...
+LL |         Ok(self)
+   |         -- ^^^^ expected `Other<<T as TryAdd>::Output>`, found `Other<T>`
+   |         |
+   |         arguments to this enum variant are incorrect
+   |
+   = note: expected struct `Other<<T as TryAdd>::Output>`
+              found struct `Other<T>`
+help: the type constructed contains `Other<T>` due to the type of the argument passed
+  --> $DIR/restrict-existing-type-bounds.rs:26:9
+   |
+LL |         Ok(self)
+   |         ^^^----^
+   |            |
+   |            this argument influences the type of `Ok`
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+help: consider further restricting this bound
+   |
+LL | impl<T: TryAdd<Error = X, Output = T>> TryAdd for Other<T> {
+   |                         ++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/suggestions/suggest-fn-ptr-for-fn-item-in-fn-ret.fixed b/tests/ui/suggestions/suggest-fn-ptr-for-fn-item-in-fn-ret.fixed
new file mode 100644 (file)
index 0000000..abb9ef9
--- /dev/null
@@ -0,0 +1,12 @@
+// run-rustfix
+
+#![allow(unused)]
+
+struct Wrapper<T>(T);
+
+fn bar() -> Wrapper<fn()> { Wrapper(foo) }
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+
+fn foo() {}
+
+fn main() {}
diff --git a/tests/ui/suggestions/suggest-fn-ptr-for-fn-item-in-fn-ret.rs b/tests/ui/suggestions/suggest-fn-ptr-for-fn-item-in-fn-ret.rs
new file mode 100644 (file)
index 0000000..d2a79c3
--- /dev/null
@@ -0,0 +1,12 @@
+// run-rustfix
+
+#![allow(unused)]
+
+struct Wrapper<T>(T);
+
+fn bar() -> _ { Wrapper(foo) }
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+
+fn foo() {}
+
+fn main() {}
diff --git a/tests/ui/suggestions/suggest-fn-ptr-for-fn-item-in-fn-ret.stderr b/tests/ui/suggestions/suggest-fn-ptr-for-fn-item-in-fn-ret.stderr
new file mode 100644 (file)
index 0000000..347a038
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/suggest-fn-ptr-for-fn-item-in-fn-ret.rs:7:13
+   |
+LL | fn bar() -> _ { Wrapper(foo) }
+   |             ^
+   |             |
+   |             not allowed in type signatures
+   |             help: replace with the correct return type: `Wrapper<fn()>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
index 34199f8c37c101d2d7236a45ece953407427910d..80cd2ca7dfc9afd0e7f732c47ed84f8d61b2af9c 100644 (file)
@@ -12,7 +12,19 @@ fn main() {
     //~^ ERROR: mismatched types [E0308]
     //~| HELP: if you meant to write a byte literal, prefix with `b`
 
+    let _a: u8 = '\x20';
+    //~^ 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 is a Unicode escape
+    foo('\u{0080}');
+    //~^ ERROR: mismatched types [E0308]
+
     // Do not issue the suggestion if the char literal isn't ASCII
     let _t: u8 = '€';
     //~^ ERROR: mismatched types [E0308]
+
+    // Do not issue the suggestion if the char literal isn't ASCII
+    foo('\u{1f980}');
+    //~^ ERROR: mismatched types [E0308]
 }
index c9c2e7498d058c7953160e03f43494977bfa6deb..3d27149f0dcf13704a737b6541e94009b4800c7c 100644 (file)
@@ -30,13 +30,54 @@ LL |     foo(b'#');
    |         ~~~~
 
 error[E0308]: mismatched types
-  --> $DIR/type-mismatch-byte-literal.rs:16:18
+  --> $DIR/type-mismatch-byte-literal.rs:15:18
+   |
+LL |     let _a: u8 = '\x20';
+   |             --   ^^^^^^ expected `u8`, found `char`
+   |             |
+   |             expected due to this
+   |
+help: if you meant to write a byte literal, prefix with `b`
+   |
+LL |     let _a: u8 = b'\x20';
+   |                  ~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch-byte-literal.rs:20:9
+   |
+LL |     foo('\u{0080}');
+   |     --- ^^^^^^^^^^ 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) {}
+   |    ^^^ ------
+
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch-byte-literal.rs:24:18
    |
 LL |     let _t: u8 = '€';
    |             --   ^^^ expected `u8`, found `char`
    |             |
    |             expected due to this
 
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch-byte-literal.rs:28:9
+   |
+LL |     foo('\u{1f980}');
+   |     --- ^^^^^^^^^^^ 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) {}
+   |    ^^^ ------
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index ce690b749f5512ae86f2c0905124a015f66d05ec..b680ce7f99013d67848469be9943f8771331ee39 100644 (file)
@@ -101,10 +101,10 @@ LL | fn is_send<T: Send>(_: T) {}
    |               ^^^^ required by this bound in `is_send`
 
 error[E0277]: `main::TestType` cannot be sent between threads safely
-  --> $DIR/negated-auto-traits-error.rs:66:13
+  --> $DIR/negated-auto-traits-error.rs:66:20
    |
 LL |     is_sync(Outer2(TestType));
-   |     ------- ^^^^^^^^^^^^^^^^ `main::TestType` cannot be sent between threads safely
+   |     -------        ^^^^^^^^ `main::TestType` cannot be sent between threads safely
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs
new file mode 100644 (file)
index 0000000..8ccb15c
--- /dev/null
@@ -0,0 +1,21 @@
+// edition:2018
+
+async fn hello() { //~ HELP try adding a return type
+    0
+    //~^ ERROR [E0308]
+}
+
+async fn world() -> () {
+    0
+    //~^ ERROR [E0308]
+}
+
+async fn suggest_await_in_async_fn_return() {
+    hello()
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider `await`ing on the `Future`
+    //~| HELP consider using a semicolon here
+    //~| SUGGESTION .await
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr
new file mode 100644 (file)
index 0000000..6a1a9f4
--- /dev/null
@@ -0,0 +1,36 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-90027-async-fn-return-suggestion.rs:4:5
+   |
+LL | async fn hello() {
+   |                  - help: try adding a return type: `-> i32`
+LL |     0
+   |     ^ expected `()`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90027-async-fn-return-suggestion.rs:9:5
+   |
+LL | async fn world() -> () {
+   |                     -- expected `()` because of return type
+LL |     0
+   |     ^ expected `()`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90027-async-fn-return-suggestion.rs:14:5
+   |
+LL |     hello()
+   |     ^^^^^^^ expected `()`, found opaque type
+   |
+   = note: expected unit type `()`
+            found opaque type `impl Future<Output = ()>`
+help: consider `await`ing on the `Future`
+   |
+LL |     hello().await
+   |            ++++++
+help: consider using a semicolon here
+   |
+LL |     hello();
+   |            +
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 79958729fc521ed1ada06422e092a769384d2377..62a99b704388fc857d527e61f96b5cf407c43a24 100644 (file)
@@ -250,7 +250,8 @@ new_pr = true
 
 [autolabel."WG-trait-system-refactor"]
 trigger_files = [
-    "compiler/rustc_trait_selection/src/solve"
+    "compiler/rustc_trait_selection/src/solve",
+    "compiler/rustc_middle/src/traits/solve.rs"
 ]
 
 [notify-zulip."I-prioritize"]
@@ -440,15 +441,15 @@ cc = ["@oli-obk", "@RalfJung", "@JakobDegen", "@davidtwco", "@celinval", "@vakar
 
 [mentions."compiler/rustc_error_messages"]
 message = "`rustc_error_messages` was changed"
-cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank", "@TaKO8Ki"]
+cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@TaKO8Ki"]
 
 [mentions."compiler/rustc_errors/src/translation.rs"]
 message = "`rustc_errors::translation` was changed"
-cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank", "@TaKO8Ki"]
+cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@TaKO8Ki"]
 
 [mentions."compiler/rustc_macros/src/diagnostics"]
 message = "`rustc_macros::diagnostics` was changed"
-cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank", "@TaKO8Ki"]
+cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@TaKO8Ki"]
 
 [mentions."compiler/rustc_target/src/spec"]
 message = """
@@ -459,6 +460,14 @@ These commits modify **compiler targets**.
 [mentions."src/doc/style-guide"]
 cc = ["@rust-lang/style"]
 
+[mentions."Cargo.lock"]
+message = """
+These commits modify the `Cargo.lock` file. Random changes to `Cargo.lock` can be introduced when switching branches and rebasing PRs. 
+This was probably unintentional and should be reverted before this PR is merged. 
+
+If this was intentional then you can ignore this comment.
+"""
+
 [assign]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/contributing.html"
@@ -466,7 +475,6 @@ contributing_url = "https://rustc-dev-guide.rust-lang.org/contributing.html"
 [assign.adhoc_groups]
 compiler-team = [
     "@cjgillot",
-    "@estebank",
     "@petrochenkov",
     "@davidtwco",
     "@oli-obk",
@@ -523,13 +531,11 @@ incremental = [
 diagnostics = [
     "@compiler-errors",
     "@davidtwco",
-    "@estebank",
     "@oli-obk",
     "@TaKO8Ki",
 ]
 parser = [
     "@davidtwco",
-    "@estebank",
     "@nnethercote",
     "@petrochenkov",
 ]