]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #107429 - tgross35:from-bytes-until-null-stabilization, r=dtolnay
authorMichael Goulet <michael@errs.io>
Thu, 9 Feb 2023 04:01:24 +0000 (20:01 -0800)
committerGitHub <noreply@github.com>
Thu, 9 Feb 2023 04:01:24 +0000 (20:01 -0800)
Stabilize feature `cstr_from_bytes_until_nul`

This PR seeks to stabilize `cstr_from_bytes_until_nul`.

Partially addresses #95027

This function has only been on nightly for about 10 months, but I think it is simple enough that there isn't harm discussing stabilization. It has also had at least a handful of mentions on both the user forum and the discord, so it seems like it's already in use or at least known.

This needs FCP still.

Comment on potential discussion points:
- eventual conversion of `CStr` to be a single thin pointer: this function will still be useful to provide a safe way to create a `CStr` after this change.
- should this return a length too, to address concerns about the `CStr` change? I don't see it as being particularly useful, and it seems less ergonomic (i.e. returning `Result<(&CStr, usize), FromBytesUntilNulError>`). I think users that also need this length without the additional `strlen` call are likely better off using a combination of other methods, but this is up for discussion
- `CString::from_vec_until_nul`: this is also useful, but it doesn't even have a nightly implementation merged yet. I propose feature gating that separately, as opposed to blocking this `CStr` implementation on that

Possible alternatives:

A user can use `from_bytes_with_nul` on a slice up to `my_slice[..my_slice.iter().find(|c| c == 0).unwrap()]`. However; that is significantly less ergonomic, and is a bit more work for the compiler to optimize compared the direct `memchr` call that this wraps.

## New stable API

```rs
// both in core::ffi

pub struct FromBytesUntilNulError(());

impl CStr {
    pub const fn from_bytes_until_nul(
        bytes: &[u8]
    ) -> Result<&CStr, FromBytesUntilNulError>
}
```

cc ```@ericseppanen``` original author, ```@Mark-Simulacrum``` original reviewer, ```@m-ou-se``` brought up some issues on the thin pointer CStr

```@rustbot``` modify labels: +T-libs-api +needs-fcp

638 files changed:
.github/ISSUE_TEMPLATE/ice.yaml
.github/workflows/ci.yml
.mailmap
Cargo.lock
compiler/rustc/Cargo.toml
compiler/rustc_abi/src/lib.rs
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/attr/mod.rs
compiler/rustc_ast/src/tokenstream.rs
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/Cargo.toml
compiler/rustc_ast_pretty/Cargo.toml
compiler/rustc_ast_pretty/src/pprust/state.rs
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/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
compiler/rustc_borrowck/src/type_check/input_output.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
compiler/rustc_builtin_macros/src/deriving/debug.rs
compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
compiler/rustc_codegen_llvm/Cargo.toml
compiler/rustc_codegen_ssa/Cargo.toml
compiler/rustc_codegen_ssa/src/codegen_attrs.rs
compiler/rustc_codegen_ssa/src/mir/rvalue.rs
compiler/rustc_const_eval/Cargo.toml
compiler/rustc_const_eval/src/interpret/cast.rs
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_data_structures/src/lib.rs
compiler/rustc_data_structures/src/profiling.rs
compiler/rustc_data_structures/src/sync.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/hir_typeck.ftl
compiler/rustc_error_messages/locales/en-US/lint.ftl
compiler/rustc_error_messages/locales/en-US/parse.ftl
compiler/rustc_error_messages/locales/en-US/passes.ftl
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/diagnostic_builder.rs
compiler/rustc_errors/src/diagnostic_impls.rs
compiler/rustc_errors/src/emitter.rs
compiler/rustc_expand/src/base.rs
compiler/rustc_expand/src/build.rs
compiler/rustc_expand/src/mbe/metavar_expr.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_hir_analysis/Cargo.toml
compiler/rustc_hir_analysis/src/astconv/mod.rs
compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
compiler/rustc_hir_analysis/src/coherence/builtin.rs
compiler/rustc_hir_analysis/src/coherence/orphan.rs
compiler/rustc_hir_analysis/src/collect.rs
compiler/rustc_hir_analysis/src/collect/type_of.rs
compiler/rustc_hir_typeck/src/callee.rs
compiler/rustc_hir_typeck/src/closure.rs
compiler/rustc_hir_typeck/src/coercion.rs
compiler/rustc_hir_typeck/src/demand.rs
compiler/rustc_hir_typeck/src/errors.rs
compiler/rustc_hir_typeck/src/expr.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/mem_categorization.rs
compiler/rustc_hir_typeck/src/method/confirm.rs
compiler/rustc_hir_typeck/src/method/mod.rs
compiler/rustc_hir_typeck/src/method/probe.rs
compiler/rustc_hir_typeck/src/op.rs
compiler/rustc_infer/Cargo.toml
compiler/rustc_infer/src/infer/canonical/query_response.rs
compiler/rustc_infer/src/infer/equate.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/higher_ranked/mod.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/infer/sub.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_macros/src/diagnostics/diagnostic_builder.rs
compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
compiler/rustc_macros/src/diagnostics/utils.rs
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/hir/map/mod.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/print/pretty.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/typeck_results.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/drop_flag_effects.rs
compiler/rustc_mir_dataflow/src/move_paths/builder.rs
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/elaborate_drops.rs
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/attr_wrapper.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/generics.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/parser/nonterminal.rs
compiler/rustc_parse/src/parser/pat.rs
compiler/rustc_parse/src/parser/stmt.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_parse_format/src/lib.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/errors.rs
compiler/rustc_passes/src/hir_id_validator.rs
compiler/rustc_passes/src/lib_features.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_privacy/Cargo.toml
compiler/rustc_query_impl/Cargo.toml
compiler/rustc_query_impl/src/plumbing.rs
compiler/rustc_query_system/src/dep_graph/graph.rs
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_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/ident.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_session/src/code_stats.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/src/def_id.rs
compiler/rustc_span/src/edition.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
compiler/rustc_trait_selection/Cargo.toml
compiler/rustc_trait_selection/src/solve/assembly.rs
compiler/rustc_trait_selection/src/solve/fulfill.rs
compiler/rustc_trait_selection/src/solve/infcx_ext.rs
compiler/rustc_trait_selection/src/solve/mod.rs
compiler/rustc_trait_selection/src/solve/project_goals.rs
compiler/rustc_trait_selection/src/solve/search_graph/cache.rs
compiler/rustc_trait_selection/src/solve/trait_goals.rs
compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/fulfill.rs
compiler/rustc_trait_selection/src/traits/object_safety.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
compiler/rustc_trait_selection/src/traits/select/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
compiler/rustc_type_ir/src/sty.rs
config.toml.example
library/alloc/src/collections/btree/borrow.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/map/entry.rs
library/alloc/src/collections/btree/map/tests.rs
library/alloc/src/collections/btree/navigate.rs
library/alloc/src/collections/btree/node.rs
library/alloc/src/string.rs
library/core/benches/char/methods.rs
library/core/benches/num/flt2dec/strategy/dragon.rs
library/core/benches/num/flt2dec/strategy/grisu.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/marker.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/slice/mod.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
library/std/src/os/fd/owned.rs
library/std/src/os/fd/raw.rs
src/bootstrap/README.md
src/bootstrap/bootstrap.py
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/defaults/config.compiler.toml
src/bootstrap/defaults/config.library.toml
src/bootstrap/download.rs
src/bootstrap/lib.rs
src/bootstrap/setup.rs
src/bootstrap/setup/tests.rs [new file with mode: 0644]
src/bootstrap/test.rs
src/ci/docker/scripts/fuchsia-test-runner.py
src/ci/github-actions/ci.yml
src/ci/run.sh
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/doc/rustc/src/platform-support/fuchsia.md
src/doc/style-guide/src/statements.md
src/etc/vscode_settings.json [new file with mode: 0644]
src/librustdoc/clean/mod.rs
src/librustdoc/html/format.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/render/write_shared.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/images/down-arrow.svg [deleted file]
src/librustdoc/html/static/images/toggle-minus.svg [deleted file]
src/librustdoc/html/static/images/toggle-plus.svg [deleted file]
src/librustdoc/html/static/js/search.js
src/librustdoc/html/static_files.rs
src/librustdoc/html/templates/page.html
src/librustdoc/json/mod.rs
src/librustdoc/markdown.rs
src/librustdoc/passes/strip_hidden.rs
src/librustdoc/visit_ast.rs
src/tools/cargo
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/rust-installer
src/tools/rustfmt/src/macros.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/bad_op_mod_by_zero.main.ConstProp.diff
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/scalar_literal_propagation.main.ConstProp.diff
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/cycle.main.CopyProp.diff
tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.mir
tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.mir
tests/mir-opt/copy-prop/issue_107511.main.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/issue_107511.rs [new file with mode: 0644]
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/inherit_overflow.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/issue_101973.inner.ConstProp.diff
tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.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/simplify_match.main.ConstProp.diff
tests/mir-opt/slice_filter.variant_a-{closure#0}.CopyProp.diff
tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff
tests/mir-opt/slice_filter.variant_b-{closure#0}.CopyProp.diff
tests/mir-opt/slice_filter.variant_b-{closure#0}.DestinationPropagation.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-ui/infinite-recursive-type-impl-trait-return.rs
tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr [new file with mode: 0644]
tests/rustdoc-ui/infinite-recursive-type-impl-trait.rs
tests/rustdoc-ui/infinite-recursive-type-impl-trait.stderr [new file with mode: 0644]
tests/rustdoc/async-fn.rs
tests/rustdoc/auxiliary/inline-default-methods.rs
tests/rustdoc/const-generics/const-generics-docs.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/generic-associated-types/gats.rs
tests/rustdoc/hidden-private.rs [new file with mode: 0644]
tests/rustdoc/impl-in-const-block.rs [new file with mode: 0644]
tests/rustdoc/inline-default-methods.rs
tests/rustdoc/inline_cross/impl_trait.rs
tests/rustdoc/issue-34928.rs
tests/rustdoc/issue-85454.rs
tests/rustdoc/redirect.rs
tests/rustdoc/reexports-priv.rs
tests/rustdoc/where.SWhere_Simd_item-decl.html
tests/rustdoc/where.SWhere_TraitWhere_item-decl.html
tests/rustdoc/where.rs
tests/rustdoc/whitespace-after-where-clause.enum.html
tests/rustdoc/whitespace-after-where-clause.enum2.html
tests/rustdoc/whitespace-after-where-clause.struct.html
tests/rustdoc/whitespace-after-where-clause.struct2.html
tests/rustdoc/whitespace-after-where-clause.trait.html
tests/rustdoc/whitespace-after-where-clause.trait2.html
tests/rustdoc/whitespace-after-where-clause.union.html
tests/rustdoc/whitespace-after-where-clause.union2.html
tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
tests/ui/associated-types/hr-associated-type-projection-1.stderr
tests/ui/async-await/dont-suggest-missing-await.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/future-as-arg.rs [new file with mode: 0644]
tests/ui/async-await/future-sizes/large-arg.rs [new file with mode: 0644]
tests/ui/async-await/future-sizes/large-arg.stdout [new file with mode: 0644]
tests/ui/async-await/generator-desc.stderr
tests/ui/async-await/issue-61076.rs
tests/ui/async-await/issue-61076.stderr
tests/ui/async-await/issue-98634.stderr
tests/ui/async-await/issues/issue-102206.stderr
tests/ui/async-await/no-const-async.stderr
tests/ui/async-await/suggest-missing-await-closure.stderr
tests/ui/async-await/suggest-missing-await.stderr
tests/ui/binop/binary-op-on-double-ref.fixed
tests/ui/binop/binary-op-on-double-ref.rs
tests/ui/binop/binary-op-on-double-ref.stderr
tests/ui/binop/issue-28837.rs
tests/ui/binop/issue-28837.stderr
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/borrowck/issue-95079-missing-move-in-nested-closure.fixed [new file with mode: 0644]
tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.rs
tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.stderr
tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.rs
tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr
tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.rs
tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.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/consts/const-eval/const-eval-query-stack.rs
tests/ui/consts/const-eval/const-eval-query-stack.stderr
tests/ui/derives/deriving-copyclone.stderr
tests/ui/deriving/deriving-all-codegen.stdout
tests/ui/did_you_mean/issue-46718-struct-pattern-dotdotdot.stderr
tests/ui/dyn-star/align.over_aligned.stderr
tests/ui/dyn-star/align.rs
tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.rs
tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.stderr
tests/ui/dyn-star/check-size-at-cast.rs
tests/ui/dyn-star/check-size-at-cast.stderr
tests/ui/dyn-star/upcast.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/ffi_const.rs
tests/ui/ffi_const.stderr
tests/ui/ffi_pure.rs
tests/ui/ffi_pure.stderr
tests/ui/ffi_returns_twice.rs
tests/ui/ffi_returns_twice.stderr
tests/ui/fmt/format-string-wrong-order.rs [new file with mode: 0644]
tests/ui/fmt/format-string-wrong-order.stderr [new file with mode: 0644]
tests/ui/fmt/respanned-literal-issue-106191.rs
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/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs
tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr
tests/ui/impl-trait/auto-trait-leak.stderr
tests/ui/impl-trait/in-trait/method-signature-matches.stderr
tests/ui/impl-trait/issue-102605.stderr
tests/ui/impl-trait/issue-99914.stderr
tests/ui/impl-trait/issues/issue-86800.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/lang-items/lang-item-missing-generator.rs [deleted file]
tests/ui/lang-items/lang-item-missing-generator.stderr [deleted file]
tests/ui/layout/valid_range_oob.stderr
tests/ui/let-else/accidental-if.stderr
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/lint/unused/issue-96606.rs [new file with mode: 0644]
tests/ui/lint/unused/issue-96606.stderr [new file with mode: 0644]
tests/ui/macros/stringify.rs
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/panics/default-backtrace-ice.stderr
tests/ui/parser/anon-enums-are-ambiguous.rs [new file with mode: 0644]
tests/ui/parser/anon-enums.rs [deleted file]
tests/ui/parser/anon-enums.stderr [deleted file]
tests/ui/parser/fake-anon-enums-in-macros.rs [deleted file]
tests/ui/parser/fn-header-semantic-fail.stderr
tests/ui/parser/issue-102806.stderr
tests/ui/parser/issues/issue-63135.stderr
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/parser/type-ascription-in-pattern.rs [new file with mode: 0644]
tests/ui/parser/type-ascription-in-pattern.stderr [new file with mode: 0644]
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/proc-macro/crt-static.rs
tests/ui/pub/pub-ident-fn-3.rs [deleted file]
tests/ui/pub/pub-ident-fn-3.stderr [deleted file]
tests/ui/pub/pub-ident-fn-or-struct-2.rs [deleted file]
tests/ui/pub/pub-ident-fn-or-struct-2.stderr [deleted file]
tests/ui/pub/pub-ident-struct-2.rs [new file with mode: 0644]
tests/ui/pub/pub-ident-struct-2.stderr [new file with mode: 0644]
tests/ui/pub/pub-ident-struct-3.rs [new file with mode: 0644]
tests/ui/pub/pub-ident-struct-3.stderr [new file with mode: 0644]
tests/ui/pub/pub-ident-struct-4.fixed [new file with mode: 0644]
tests/ui/pub/pub-ident-struct-4.rs [new file with mode: 0644]
tests/ui/pub/pub-ident-struct-4.stderr [new file with mode: 0644]
tests/ui/query-system/no-query-in-printing-during-query-descr.rs [new file with mode: 0644]
tests/ui/query-system/no-query-in-printing-during-query-descr.stderr [new file with mode: 0644]
tests/ui/recursion/issue-83150.stderr
tests/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr
tests/ui/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs [new file with mode: 0644]
tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs [new file with mode: 0644]
tests/ui/stats/hir-stats.rs
tests/ui/structs-enums/struct-enum-ignoring-field-with-underscore.rs
tests/ui/structs-enums/struct-enum-ignoring-field-with-underscore.stderr
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/if-then-neeing-semi.rs
tests/ui/suggestions/if-then-neeing-semi.stderr
tests/ui/suggestions/issue-81839.stderr
tests/ui/suggestions/match-prev-arm-needing-semi.rs
tests/ui/suggestions/match-prev-arm-needing-semi.stderr
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/track-diagnostics/track4.stderr
tests/ui/traits/negative-impls/negated-auto-traits-error.stderr
tests/ui/traits/new-solver/pointer-like.rs [new file with mode: 0644]
tests/ui/traits/new-solver/pointer-like.stderr [new file with mode: 0644]
tests/ui/traits/new-solver/pointer-sized.rs [deleted file]
tests/ui/traits/new-solver/pointer-sized.stderr [deleted file]
tests/ui/treat-err-as-bug/delay_span_bug.stderr
tests/ui/treat-err-as-bug/err.stderr
tests/ui/type-alias-impl-trait/issue-98604.stderr
tests/ui/typeck/issue-107775.rs [new file with mode: 0644]
tests/ui/typeck/issue-107775.stderr [new file with mode: 0644]
tests/ui/typeck/issue-89856.fixed [new file with mode: 0644]
tests/ui/typeck/issue-89856.rs
tests/ui/typeck/issue-89856.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]
tests/ui/uninhabited/issue-107505.rs [new file with mode: 0644]
tests/ui/unpretty/ast-const-trait-bound.rs [new file with mode: 0644]
tests/ui/unpretty/ast-const-trait-bound.stdout [new file with mode: 0644]
tests/ui/where-clauses/self-in-where-clause-allowed.rs [new file with mode: 0644]
tests/ui/where-clauses/self-in-where-clause-allowed.stderr [new file with mode: 0644]
triagebot.toml
x.py

index 8d25bb41c08066fcf5d2d99cc18d9393c2377093..7bec05cc575a875239d1ba10cc269c7827e68ada 100644 (file)
@@ -1,4 +1,4 @@
-name: Internal Compiler Error (Structured form)
+name: Internal Compiler Error (for use by automated tooling)
 description: For now, you'll want to use the other ICE template, as GitHub forms have strict limits on the size of fields so backtraces cannot be pasted directly.
 labels: ["C-bug", "I-ICE", "T-compiler"]
 title: "[ICE]: "
index 552680f06f66dd58390c69f5b1c09f3c4205acc8..b51105750c82cc9aa428298d520959ab20071409 100644 (file)
@@ -37,6 +37,7 @@ jobs:
     name: PR
     env:
       CI_JOB_NAME: "${{ matrix.name }}"
+      CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
       SCCACHE_BUCKET: rust-lang-ci-sccache2
       TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
       CACHE_DOMAIN: ci-caches.rust-lang.org
@@ -59,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:
@@ -162,6 +162,7 @@ jobs:
     name: auto
     env:
       CI_JOB_NAME: "${{ matrix.name }}"
+      CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
       SCCACHE_BUCKET: rust-lang-ci-sccache2
       DEPLOY_BUCKET: rust-lang-ci2
       TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
@@ -325,7 +326,7 @@ jobs:
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
               DIST_REQUIRE_ALL_TOOLS: 1
-            os: macos-12-xl
+            os: macos-latest
           - name: dist-apple-various
             env:
               SCRIPT: "./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim"
@@ -336,7 +337,7 @@ jobs:
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
-            os: macos-12-xl
+            os: macos-latest
           - name: dist-x86_64-apple-alt
             env:
               SCRIPT: "./x.py dist bootstrap --include-default-paths"
@@ -347,7 +348,7 @@ jobs:
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
-            os: macos-12-xl
+            os: macos-latest
           - name: x86_64-apple-1
             env:
               SCRIPT: "./x.py --stage 2 test --exclude tests/ui --exclude tests/rustdoc --exclude tests/run-make-fulldeps"
@@ -358,7 +359,7 @@ jobs:
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
-            os: macos-12-xl
+            os: macos-latest
           - name: x86_64-apple-2
             env:
               SCRIPT: "./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps"
@@ -369,7 +370,7 @@ jobs:
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
-            os: macos-12-xl
+            os: macos-latest
           - name: dist-aarch64-apple
             env:
               SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2"
@@ -384,7 +385,7 @@ jobs:
               NO_OVERFLOW_CHECKS: 1
               DIST_REQUIRE_ALL_TOOLS: 1
               JEMALLOC_SYS_WITH_LG_PAGE: 14
-            os: macos-12-xl
+            os: macos-latest
           - name: x86_64-msvc-1
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
@@ -584,6 +585,7 @@ jobs:
     name: try
     env:
       CI_JOB_NAME: "${{ matrix.name }}"
+      CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
       SCCACHE_BUCKET: rust-lang-ci-sccache2
       DEPLOY_BUCKET: rust-lang-ci2
       TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
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 b35892ccd523e9cba17f412e8b7817e58f24deb5..ad01ef5e41f162a918ad976df5ec3beb88a80c13 100644 (file)
@@ -127,6 +127,12 @@ version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271"
 
+[[package]]
+name = "arrayvec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
+
 [[package]]
 name = "arrayvec"
 version = "0.7.0"
@@ -342,7 +348,7 @@ dependencies = [
 
 [[package]]
 name = "cargo"
-version = "0.69.0"
+version = "0.70.0"
 dependencies = [
  "anyhow",
  "base64",
@@ -407,7 +413,7 @@ dependencies = [
  "unicode-xid",
  "url",
  "walkdir",
- "winapi",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -436,7 +442,7 @@ name = "cargo-credential-wincred"
 version = "0.2.0"
 dependencies = [
  "cargo-credential",
- "winapi",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -496,7 +502,7 @@ dependencies = [
  "time 0.3.17",
  "toml_edit",
  "url",
- "winapi",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -516,7 +522,7 @@ dependencies = [
  "shell-escape",
  "tempfile",
  "walkdir",
- "winapi",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -791,7 +797,7 @@ dependencies = [
 name = "clippy_utils"
 version = "0.1.69"
 dependencies = [
- "arrayvec",
+ "arrayvec 0.7.0",
  "if_chain",
  "itertools",
  "rustc-semver",
@@ -2217,7 +2223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
 dependencies = [
  "libc",
- "windows-sys",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -2229,7 +2235,7 @@ dependencies = [
  "hermit-abi 0.2.6",
  "io-lifetimes",
  "rustix",
- "windows-sys",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -2670,7 +2676,7 @@ version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123"
 dependencies = [
- "windows-sys",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -2987,7 +2993,7 @@ dependencies = [
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-sys",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -3567,6 +3573,7 @@ dependencies = [
  "jemalloc-sys",
  "rustc_codegen_ssa",
  "rustc_driver",
+ "rustc_driver_impl",
  "rustc_smir",
 ]
 
@@ -3688,7 +3695,6 @@ dependencies = [
 name = "rustc_ast_lowering"
 version = "0.0.0"
 dependencies = [
- "rustc_arena",
  "rustc_ast",
  "rustc_ast_pretty",
  "rustc_data_structures",
@@ -3697,7 +3703,6 @@ dependencies = [
  "rustc_index",
  "rustc_macros",
  "rustc_middle",
- "rustc_query_system",
  "rustc_session",
  "rustc_span",
  "rustc_target",
@@ -3730,7 +3735,6 @@ name = "rustc_ast_pretty"
 version = "0.0.0"
 dependencies = [
  "rustc_ast",
- "rustc_parse_format",
  "rustc_span",
 ]
 
@@ -3837,7 +3841,6 @@ dependencies = [
  "rustc_metadata",
  "rustc_middle",
  "rustc_query_system",
- "rustc_serialize",
  "rustc_session",
  "rustc_span",
  "rustc_symbol_mangling",
@@ -3863,7 +3866,6 @@ dependencies = [
  "rustc_arena",
  "rustc_ast",
  "rustc_attr",
- "rustc_const_eval",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fs_util",
@@ -3904,7 +3906,6 @@ dependencies = [
  "rustc_macros",
  "rustc_middle",
  "rustc_mir_dataflow",
- "rustc_query_system",
  "rustc_session",
  "rustc_span",
  "rustc_target",
@@ -3917,7 +3918,7 @@ dependencies = [
 name = "rustc_data_structures"
 version = "0.0.0"
 dependencies = [
- "arrayvec",
+ "arrayvec 0.7.0",
  "bitflags",
  "cfg-if",
  "ena",
@@ -3946,6 +3947,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 +4100,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",
@@ -4170,7 +4175,7 @@ dependencies = [
 name = "rustc_index"
 version = "0.0.0"
 dependencies = [
- "arrayvec",
+ "arrayvec 0.7.0",
  "rustc_macros",
  "rustc_serialize",
  "smallvec",
@@ -4187,7 +4192,6 @@ dependencies = [
  "rustc_macros",
  "rustc_middle",
  "rustc_serialize",
- "rustc_session",
  "rustc_span",
  "rustc_target",
  "smallvec",
@@ -4230,7 +4234,6 @@ dependencies = [
  "rustc_privacy",
  "rustc_query_impl",
  "rustc_resolve",
- "rustc_serialize",
  "rustc_session",
  "rustc_span",
  "rustc_symbol_mangling",
@@ -4396,7 +4399,6 @@ dependencies = [
  "rustc_apfloat",
  "rustc_arena",
  "rustc_ast",
- "rustc_attr",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_hir",
@@ -4428,7 +4430,6 @@ dependencies = [
  "rustc_macros",
  "rustc_middle",
  "rustc_serialize",
- "rustc_session",
  "rustc_span",
  "rustc_target",
  "smallvec",
@@ -4559,7 +4560,6 @@ dependencies = [
  "rustc_middle",
  "rustc_session",
  "rustc_span",
- "rustc_trait_selection",
  "tracing",
 ]
 
@@ -4580,7 +4580,6 @@ dependencies = [
  "rustc_serialize",
  "rustc_session",
  "rustc_span",
- "rustc_target",
  "thin-vec",
  "tracing",
 ]
@@ -4781,7 +4780,6 @@ dependencies = [
  "rustc_hir",
  "rustc_index",
  "rustc_infer",
- "rustc_lint_defs",
  "rustc_macros",
  "rustc_middle",
  "rustc_parse_format",
@@ -4803,7 +4801,6 @@ dependencies = [
  "chalk-ir",
  "chalk-solve",
  "rustc_ast",
- "rustc_attr",
  "rustc_data_structures",
  "rustc_hir",
  "rustc_index",
@@ -4875,7 +4872,7 @@ dependencies = [
 name = "rustdoc"
 version = "0.0.0"
 dependencies = [
- "arrayvec",
+ "arrayvec 0.7.0",
  "askama",
  "expect-test",
  "itertools",
@@ -4978,7 +4975,7 @@ dependencies = [
  "io-lifetimes",
  "libc",
  "linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -5384,9 +5381,9 @@ dependencies = [
 
 [[package]]
 name = "strip-ansi-escapes"
-version = "0.1.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d63676e2abafa709460982ddc02a3bb586b6d15a49b75c212e06edd3933acee"
+checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8"
 dependencies = [
  "vte",
 ]
@@ -5508,7 +5505,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
 dependencies = [
  "rustix",
- "windows-sys",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -6098,9 +6095,9 @@ checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7"
 
 [[package]]
 name = "utf8parse"
-version = "0.1.1"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
+checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
 
 [[package]]
 name = "uuid"
@@ -6131,11 +6128,23 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
 name = "vte"
-version = "0.3.3"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf"
+checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983"
 dependencies = [
+ "arrayvec 0.5.2",
  "utf8parse",
+ "vte_generate_state_changes",
+]
+
+[[package]]
+name = "vte_generate_state_changes"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff"
+dependencies = [
+ "proc-macro2",
+ "quote",
 ]
 
 [[package]]
@@ -6260,47 +6269,71 @@ dependencies = [
  "windows_x86_64_msvc",
 ]
 
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
 
 [[package]]
 name = "writeable"
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 8ad3270c5103ec24cbd11429b4f7cd7984fba6fd..f2258fecfeafc6645a4b78cdd142470f6328eeb2 100644 (file)
@@ -1826,6 +1826,13 @@ pub enum LitKind {
 }
 
 impl LitKind {
+    pub fn str(&self) -> Option<Symbol> {
+        match *self {
+            LitKind::Str(s, _) => Some(s),
+            _ => None,
+        }
+    }
+
     /// Returns `true` if this literal is a string.
     pub fn is_str(&self) -> bool {
         matches!(self, LitKind::Str(..))
index c6b6207b3186e85442b1c388c221b6974b0306b3..cd60506dd80795b1e9314ec6aeaec8f668267526 100644 (file)
@@ -140,17 +140,14 @@ pub fn name_or_empty(&self) -> Symbol {
 
     pub fn value_str(&self) -> Option<Symbol> {
         match &self.kind {
-            AttrKind::Normal(normal) => normal.item.meta_kind().and_then(|kind| kind.value_str()),
+            AttrKind::Normal(normal) => normal.item.value_str(),
             AttrKind::DocComment(..) => None,
         }
     }
 
     pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
         match &self.kind {
-            AttrKind::Normal(normal) => match normal.item.meta_kind() {
-                Some(MetaItemKind::List(list)) => Some(list),
-                _ => None,
-            },
+            AttrKind::Normal(normal) => normal.item.meta_item_list(),
             AttrKind::DocComment(..) => None,
         }
     }
@@ -216,6 +213,20 @@ pub fn name_value_literal_span(&self) -> Option<Span> {
     }
 }
 
+impl AttrArgsEq {
+    fn value_str(&self) -> Option<Symbol> {
+        match self {
+            AttrArgsEq::Ast(expr) => match expr.kind {
+                ExprKind::Lit(token_lit) => {
+                    LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
+                }
+                _ => None,
+            },
+            AttrArgsEq::Hir(lit) => lit.kind.str(),
+        }
+    }
+}
+
 impl AttrItem {
     pub fn span(&self) -> Span {
         self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
@@ -228,6 +239,22 @@ pub fn meta(&self, span: Span) -> Option<MetaItem> {
     pub fn meta_kind(&self) -> Option<MetaItemKind> {
         MetaItemKind::from_attr_args(&self.args)
     }
+
+    fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
+        match &self.args {
+            AttrArgs::Delimited(args) if args.delim == MacDelimiter::Parenthesis => {
+                MetaItemKind::list_from_tokens(args.tokens.clone())
+            }
+            AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None,
+        }
+    }
+
+    fn value_str(&self) -> Option<Symbol> {
+        match &self.args {
+            AttrArgs::Eq(_, args) => args.value_str(),
+            AttrArgs::Delimited(_) | AttrArgs::Empty => None,
+        }
+    }
 }
 
 impl Attribute {
@@ -247,13 +274,11 @@ pub fn is_doc_comment(&self) -> bool {
     /// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
     /// * `#[doc(...)]` returns `None`.
     pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
-        match self.kind {
-            AttrKind::DocComment(kind, data) => Some((data, kind)),
-            AttrKind::Normal(ref normal) if normal.item.path == sym::doc => normal
-                .item
-                .meta_kind()
-                .and_then(|kind| kind.value_str())
-                .map(|data| (data, CommentKind::Line)),
+        match &self.kind {
+            AttrKind::DocComment(kind, data) => Some((*data, *kind)),
+            AttrKind::Normal(normal) if normal.item.path == sym::doc => {
+                normal.item.value_str().map(|s| (s, CommentKind::Line))
+            }
             _ => None,
         }
     }
@@ -265,9 +290,7 @@ pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
     pub fn doc_str(&self) -> Option<Symbol> {
         match &self.kind {
             AttrKind::DocComment(.., data) => Some(*data),
-            AttrKind::Normal(normal) if normal.item.path == sym::doc => {
-                normal.item.meta_kind().and_then(|kind| kind.value_str())
-            }
+            AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(),
             _ => None,
         }
     }
@@ -508,15 +531,12 @@ fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
 impl MetaItemKind {
     pub fn value_str(&self) -> Option<Symbol> {
         match self {
-            MetaItemKind::NameValue(v) => match v.kind {
-                LitKind::Str(s, _) => Some(s),
-                _ => None,
-            },
+            MetaItemKind::NameValue(v) => v.kind.str(),
             _ => None,
         }
     }
 
-    fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> {
+    fn list_from_tokens(tokens: TokenStream) -> Option<Vec<NestedMetaItem>> {
         let mut tokens = tokens.into_trees().peekable();
         let mut result = Vec::new();
         while tokens.peek().is_some() {
@@ -527,7 +547,7 @@ fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> {
                 _ => return None,
             }
         }
-        Some(MetaItemKind::List(result))
+        Some(result)
     }
 
     fn name_value_from_tokens(
@@ -551,7 +571,7 @@ fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
                 dspan: _,
                 delim: MacDelimiter::Parenthesis,
                 tokens,
-            }) => MetaItemKind::list_from_tokens(tokens.clone()),
+            }) => MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List),
             AttrArgs::Delimited(..) => None,
             AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => match expr.kind {
                 ExprKind::Lit(token_lit) => {
@@ -573,7 +593,7 @@ fn from_tokens(
             Some(TokenTree::Delimited(_, Delimiter::Parenthesis, inner_tokens)) => {
                 let inner_tokens = inner_tokens.clone();
                 tokens.next();
-                MetaItemKind::list_from_tokens(inner_tokens)
+                MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
             }
             Some(TokenTree::Delimited(..)) => None,
             Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
index fabd43a1618a4387fa8af8680fe8a52f17af90d1..f0a6a5e0725860b5f090f8f6a12223ad13b868f1 100644 (file)
@@ -41,7 +41,8 @@
 /// Nothing special happens to misnamed or misplaced `SubstNt`s.
 #[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
 pub enum TokenTree {
-    /// A single token.
+    /// A single token. Should never be `OpenDelim` or `CloseDelim`, because
+    /// delimiters are implicitly represented by `Delimited`.
     Token(Token, Spacing),
     /// A delimited sequence of token trees.
     Delimited(DelimSpan, Delimiter, TokenStream),
@@ -388,12 +389,12 @@ pub fn len(&self) -> usize {
         self.0.len()
     }
 
-    pub fn trees(&self) -> CursorRef<'_> {
-        CursorRef::new(self)
+    pub fn trees(&self) -> RefTokenTreeCursor<'_> {
+        RefTokenTreeCursor::new(self)
     }
 
-    pub fn into_trees(self) -> Cursor {
-        Cursor::new(self)
+    pub fn into_trees(self) -> TokenTreeCursor {
+        TokenTreeCursor::new(self)
     }
 
     /// Compares two `TokenStream`s, checking equality without regarding span information.
@@ -551,16 +552,17 @@ pub fn push_stream(&mut self, stream: TokenStream) {
     }
 }
 
-/// By-reference iterator over a [`TokenStream`].
+/// By-reference iterator over a [`TokenStream`], that produces `&TokenTree`
+/// items.
 #[derive(Clone)]
-pub struct CursorRef<'t> {
+pub struct RefTokenTreeCursor<'t> {
     stream: &'t TokenStream,
     index: usize,
 }
 
-impl<'t> CursorRef<'t> {
+impl<'t> RefTokenTreeCursor<'t> {
     fn new(stream: &'t TokenStream) -> Self {
-        CursorRef { stream, index: 0 }
+        RefTokenTreeCursor { stream, index: 0 }
     }
 
     pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
@@ -568,7 +570,7 @@ pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
     }
 }
 
-impl<'t> Iterator for CursorRef<'t> {
+impl<'t> Iterator for RefTokenTreeCursor<'t> {
     type Item = &'t TokenTree;
 
     fn next(&mut self) -> Option<&'t TokenTree> {
@@ -579,15 +581,16 @@ fn next(&mut self) -> Option<&'t TokenTree> {
     }
 }
 
-/// Owning by-value iterator over a [`TokenStream`].
+/// Owning by-value iterator over a [`TokenStream`], that produces `TokenTree`
+/// items.
 // FIXME: Many uses of this can be replaced with by-reference iterator to avoid clones.
 #[derive(Clone)]
-pub struct Cursor {
+pub struct TokenTreeCursor {
     pub stream: TokenStream,
     index: usize,
 }
 
-impl Iterator for Cursor {
+impl Iterator for TokenTreeCursor {
     type Item = TokenTree;
 
     fn next(&mut self) -> Option<TokenTree> {
@@ -598,9 +601,9 @@ fn next(&mut self) -> Option<TokenTree> {
     }
 }
 
-impl Cursor {
+impl TokenTreeCursor {
     fn new(stream: TokenStream) -> Self {
-        Cursor { stream, index: 0 }
+        TokenTreeCursor { stream, index: 0 }
     }
 
     #[inline]
@@ -614,6 +617,15 @@ pub fn next_ref(&mut self) -> Option<&TokenTree> {
     pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
         self.stream.0.get(self.index + n)
     }
+
+    // Replace the previously obtained token tree with `tts`, and rewind to
+    // just before them.
+    pub fn replace_prev_and_rewind(&mut self, tts: Vec<TokenTree>) {
+        assert!(self.index > 0);
+        self.index -= 1;
+        let stream = Lrc::make_mut(&mut self.stream.0);
+        stream.splice(self.index..self.index + 1, tts);
+    }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
index e7b2e4b1cb4b072a4d300e0e20b978fa16fb2ee4..bdb1879ec201d9c74fea9483e7ff19d3a8abf5eb 100644 (file)
@@ -403,8 +403,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
             walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref);
             visitor.visit_ty(&mutable_type.ty)
         }
-        TyKind::Tup(tys) => {
-            walk_list!(visitor, visit_ty, tys);
+        TyKind::Tup(tuple_element_types) => {
+            walk_list!(visitor, visit_ty, tuple_element_types);
         }
         TyKind::BareFn(function_declaration) => {
             walk_list!(visitor, visit_generic_param, &function_declaration.generic_params);
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 fa8567eac609074925d82b465c6bae7feaf21ea9..cd621bc67a1de9328e4fec0d2ebc27fa721df944 100644 (file)
@@ -131,7 +131,7 @@ pub fn print_crate<'a>(
 
         // Currently, in Rust 2018 we don't have `extern crate std;` at the crate
         // root, so this is not needed, and actually breaks things.
-        if edition.rust_2015() {
+        if edition.is_rust_2015() {
             // `#![no_std]`
             let fake_attr = attr::mk_attr_word(g, ast::AttrStyle::Inner, sym::no_std, DUMMY_SP);
             s.print_attribute(&fake_attr);
@@ -1567,8 +1567,18 @@ pub fn print_type_bounds(&mut self, bounds: &[ast::GenericBound]) {
 
             match bound {
                 GenericBound::Trait(tref, modifier) => {
-                    if modifier == &TraitBoundModifier::Maybe {
-                        self.word("?");
+                    match modifier {
+                        TraitBoundModifier::None => {}
+                        TraitBoundModifier::Maybe => {
+                            self.word("?");
+                        }
+                        TraitBoundModifier::MaybeConst => {
+                            self.word_space("~const");
+                        }
+                        TraitBoundModifier::MaybeConstMaybe => {
+                            self.word_space("~const");
+                            self.word("?");
+                        }
                     }
                     self.print_poly_trait_ref(tref);
                 }
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..3006e27e1d5b53882bfaa8528bcee7b4f8ab849b 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={:?}",
@@ -1137,7 +1139,7 @@ fn explain_captures(
                         if let ty::Adt(def, substs) = ty.kind()
                             && Some(def.did()) == tcx.lang_items().pin_type()
                             && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
-                            && let self_ty = infcx.replace_bound_vars_with_fresh_vars(
+                            && let self_ty = infcx.instantiate_binder_with_fresh_vars(
                                 fn_call_span,
                                 LateBoundRegionConversionTime::FnCall,
                                 tcx.fn_sig(method_did).subst(tcx, method_substs).input(0),
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 87db08ef5b5108e3b6439883ce5d8bb869f90967..7901a5046abad12a466cf045b9591d4fe618f5f1 100644 (file)
@@ -583,10 +583,12 @@ fn report_fnmut_error(
         let err = FnMutError {
             span: *span,
             ty_err: match output_ty.kind() {
-                ty::Closure(_, _) => FnMutReturnTypeErr::ReturnClosure { span: *span },
                 ty::Generator(def, ..) if self.infcx.tcx.generator_is_async(*def) => {
                     FnMutReturnTypeErr::ReturnAsyncBlock { span: *span }
                 }
+                _ if output_ty.contains_closure() => {
+                    FnMutReturnTypeErr::ReturnClosure { span: *span }
+                }
                 _ => FnMutReturnTypeErr::ReturnRef { span: *span },
             },
         };
@@ -997,7 +999,7 @@ fn suggest_adding_lifetime_params(
     fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
         let map = self.infcx.tcx.hir();
         let body_id = map.body_owned_by(self.mir_def_id());
-        let expr = &map.body(body_id).value;
+        let expr = &map.body(body_id).value.peel_blocks();
         let mut closure_span = None::<rustc_span::Span>;
         match expr.kind {
             hir::ExprKind::MethodCall(.., args, _) => {
@@ -1012,20 +1014,14 @@ fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
                     }
                 }
             }
-            hir::ExprKind::Block(blk, _) => {
-                if let Some(expr) = blk.expr {
-                    // only when the block is a closure
-                    if let hir::ExprKind::Closure(hir::Closure {
-                        capture_clause: hir::CaptureBy::Ref,
-                        body,
-                        ..
-                    }) = expr.kind
-                    {
-                        let body = map.body(*body);
-                        if !matches!(body.generator_kind, Some(hir::GeneratorKind::Async(..))) {
-                            closure_span = Some(expr.span.shrink_to_lo());
-                        }
-                    }
+            hir::ExprKind::Closure(hir::Closure {
+                capture_clause: hir::CaptureBy::Ref,
+                body,
+                ..
+            }) => {
+                let body = map.body(*body);
+                if !matches!(body.generator_kind, Some(hir::GeneratorKind::Async(..))) {
+                    closure_span = Some(expr.span.shrink_to_lo());
                 }
             }
             _ => {}
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 fa9ea769a14f79607e86c7d69dafbec2216b5c1a..c6b78df9a5ff033db5671483da5f41c53ae772c0 100644 (file)
@@ -38,7 +38,7 @@ pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
         // so that they represent the view from "inside" the closure.
         let user_provided_sig = self
             .instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig);
-        let user_provided_sig = self.infcx.replace_bound_vars_with_fresh_vars(
+        let user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars(
             body.span,
             LateBoundRegionConversionTime::FnCall,
             user_provided_sig,
index 2605a1491fb35427609d13dd00475820eb2fdfc1..5b52846562f87f64db5d65d5095c64850fd11904 100644 (file)
@@ -1484,7 +1484,10 @@ fn check_call_dest(
                 }
             }
             None => {
-                if !sig.output().is_privately_uninhabited(self.tcx(), self.param_env) {
+                // The signature in this call can reference region variables,
+                // so erase them before calling a query.
+                let output_ty = self.tcx().erase_regions(sig.output());
+                if !output_ty.is_privately_uninhabited(self.tcx(), self.param_env) {
                     span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
                 }
             }
@@ -2533,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 88d454fbc11230f5ad04f55269112bd8789dc1d9..bad47db0de1d4e16103d6724d786eb479d480ab7 100644 (file)
@@ -29,16 +29,30 @@ fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOr
                         cx.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
                     };
 
-                    // We received `&T` arguments. Convert them to `T` by
-                    // stripping `&` or adding `*`. This isn't necessary for
-                    // type checking, but it results in much better error
-                    // messages if something goes wrong.
+                    // We received arguments of type `&T`. Convert them to type `T` by stripping
+                    // any leading `&` or adding `*`. This isn't necessary for type checking, but
+                    // it results in better error messages if something goes wrong.
+                    //
+                    // Note: for arguments that look like `&{ x }`, which occur with packed
+                    // structs, this would cause expressions like `{ self.x } == { other.x }`,
+                    // which isn't valid Rust syntax. This wouldn't break compilation because these
+                    // AST nodes are constructed within the compiler. But it would mean that code
+                    // printed by `-Zunpretty=expanded` (or `cargo expand`) would have invalid
+                    // syntax, which would be suboptimal. So we wrap these in parens, giving
+                    // `({ self.x }) == ({ other.x })`, which is valid syntax.
                     let convert = |expr: &P<Expr>| {
                         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) =
                             &expr.kind
                         {
-                            inner.clone()
+                            if let ExprKind::Block(..) = &inner.kind {
+                                // `&{ x }` form: remove the `&`, add parens.
+                                cx.expr_paren(field.span, inner.clone())
+                            } else {
+                                // `&x` form: remove the `&`.
+                                inner.clone()
+                            }
                         } else {
+                            // No leading `&`: add a leading `*`.
                             cx.expr_deref(field.span, expr.clone())
                         }
                     };
index 897048f64211e37d509d31457f1d71cf4d7edf3f..e8a353b1c8fcc61474ad64cb001971ede5a5b67a 100644 (file)
@@ -76,6 +76,21 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
     // The number of fields that can be handled without an array.
     const CUTOFF: usize = 5;
 
+    fn expr_for_field(
+        cx: &ExtCtxt<'_>,
+        field: &FieldInfo,
+        index: usize,
+        len: usize,
+    ) -> ast::ptr::P<ast::Expr> {
+        if index < len - 1 {
+            field.self_expr.clone()
+        } else {
+            // Unsized types need an extra indirection, but only the last field
+            // may be unsized.
+            cx.expr_addr_of(field.span, field.self_expr.clone())
+        }
+    }
+
     if fields.is_empty() {
         // Special case for no fields.
         let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
@@ -98,8 +113,8 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
                 let name = cx.expr_str(field.span, field.name.unwrap().name);
                 args.push(name);
             }
-            // Use an extra indirection to make sure this works for unsized types.
-            let field = cx.expr_addr_of(field.span, field.self_expr.clone());
+
+            let field = expr_for_field(cx, field, i, fields.len());
             args.push(field);
         }
         let expr = cx.expr_call_global(span, fn_path_debug, args);
@@ -109,13 +124,13 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
         let mut name_exprs = Vec::with_capacity(fields.len());
         let mut value_exprs = Vec::with_capacity(fields.len());
 
-        for field in fields {
+        for i in 0..fields.len() {
+            let field = &fields[i];
             if is_struct {
                 name_exprs.push(cx.expr_str(field.span, field.name.unwrap().name));
             }
 
-            // Use an extra indirection to make sure this works for unsized types.
-            let field = cx.expr_addr_of(field.span, field.self_expr.clone());
+            let field = expr_for_field(cx, field, i, fields.len());
             value_exprs.push(field);
         }
 
@@ -138,7 +153,10 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
         let path_debug = cx.path_global(span, cx.std_path(&[sym::fmt, sym::Debug]));
         let ty_dyn_debug = cx.ty(
             span,
-            ast::TyKind::TraitObject(vec![cx.trait_bound(path_debug)], ast::TraitObjectSyntax::Dyn),
+            ast::TyKind::TraitObject(
+                vec![cx.trait_bound(path_debug, false)],
+                ast::TraitObjectSyntax::Dyn,
+            ),
         );
         let ty_slice = cx.ty(
             span,
index 97de40bac34661f12d86e27e12a139ae76ebdd36..a8c0aeb787078140ba2cab22b851002e2bbdf3f6 100644 (file)
@@ -605,18 +605,26 @@ fn create_derived_impl(
                     let bounds: Vec<_> = self
                         .additional_bounds
                         .iter()
-                        .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
+                        .map(|p| {
+                            cx.trait_bound(
+                                p.to_path(cx, self.span, type_ident, generics),
+                                self.is_const,
+                            )
+                        })
                         .chain(
                             // Add a bound for the current trait.
                             self.skip_path_as_bound
                                 .not()
-                                .then(|| cx.trait_bound(trait_path.clone())),
+                                .then(|| cx.trait_bound(trait_path.clone(), self.is_const)),
                         )
                         .chain({
                             // Add a `Copy` bound if required.
                             if is_packed && self.needs_copy_as_bound_if_packed {
                                 let p = deriving::path_std!(marker::Copy);
-                                Some(cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
+                                Some(cx.trait_bound(
+                                    p.to_path(cx, self.span, type_ident, generics),
+                                    self.is_const,
+                                ))
                             } else {
                                 None
                             }
@@ -694,18 +702,24 @@ fn create_derived_impl(
                         let mut bounds: Vec<_> = self
                             .additional_bounds
                             .iter()
-                            .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
+                            .map(|p| {
+                                cx.trait_bound(
+                                    p.to_path(cx, self.span, type_ident, generics),
+                                    self.is_const,
+                                )
+                            })
                             .collect();
 
                         // Require the current trait.
-                        bounds.push(cx.trait_bound(trait_path.clone()));
+                        bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
 
                         // Add a `Copy` bound if required.
                         if is_packed && self.needs_copy_as_bound_if_packed {
                             let p = deriving::path_std!(marker::Copy);
-                            bounds.push(
-                                cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)),
-                            );
+                            bounds.push(cx.trait_bound(
+                                p.to_path(cx, self.span, type_ident, generics),
+                                self.is_const,
+                            ));
                         }
 
                         let predicate = ast::WhereBoundPredicate {
index c6f5f5d080706be7d41c7c52d8840edf6b545b42..aabd5b1f773f70baa3691862eb4a190f8068a8fb 100644 (file)
@@ -154,7 +154,7 @@ fn mk_ty_param(
         .iter()
         .map(|b| {
             let path = b.to_path(cx, span, self_ident, self_generics);
-            cx.trait_bound(path)
+            cx.trait_bound(path, false)
         })
         .collect();
     cx.typaram(span, Ident::new(name, span), bounds, None)
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 87b819ebc9849504a6be8219bcfa67bda680c416..3ebbb2cbdfb8e239b0eeb7d20e806ab2ff1154ec 100644 (file)
@@ -85,55 +85,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
         } else if attr.has_name(sym::rustc_allocator) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
         } else if attr.has_name(sym::ffi_returns_twice) {
-            if tcx.is_foreign_item(did) {
-                codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
-            } else {
-                // `#[ffi_returns_twice]` is only allowed `extern fn`s.
-                struct_span_err!(
-                    tcx.sess,
-                    attr.span,
-                    E0724,
-                    "`#[ffi_returns_twice]` may only be used on foreign functions"
-                )
-                .emit();
-            }
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
         } else if attr.has_name(sym::ffi_pure) {
-            if tcx.is_foreign_item(did) {
-                if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
-                    // `#[ffi_const]` functions cannot be `#[ffi_pure]`
-                    struct_span_err!(
-                        tcx.sess,
-                        attr.span,
-                        E0757,
-                        "`#[ffi_const]` function cannot be `#[ffi_pure]`"
-                    )
-                    .emit();
-                } else {
-                    codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
-                }
-            } else {
-                // `#[ffi_pure]` is only allowed on foreign functions
-                struct_span_err!(
-                    tcx.sess,
-                    attr.span,
-                    E0755,
-                    "`#[ffi_pure]` may only be used on foreign functions"
-                )
-                .emit();
-            }
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
         } else if attr.has_name(sym::ffi_const) {
-            if tcx.is_foreign_item(did) {
-                codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
-            } else {
-                // `#[ffi_const]` is only allowed on foreign functions
-                struct_span_err!(
-                    tcx.sess,
-                    attr.span,
-                    E0756,
-                    "`#[ffi_const]` may only be used on foreign functions"
-                )
-                .emit();
-            }
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
         } else if attr.has_name(sym::rustc_nounwind) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
         } else if attr.has_name(sym::rustc_reallocator) {
@@ -363,74 +319,62 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
                 }
             }
         } else if attr.has_name(sym::instruction_set) {
-            codegen_fn_attrs.instruction_set = match attr.meta_kind() {
-                Some(MetaItemKind::List(ref items)) => match items.as_slice() {
-                    [NestedMetaItem::MetaItem(set)] => {
-                        let segments =
-                            set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
-                        match segments.as_slice() {
-                            [sym::arm, sym::a32] | [sym::arm, sym::t32] => {
-                                if !tcx.sess.target.has_thumb_interworking {
-                                    struct_span_err!(
-                                        tcx.sess.diagnostic(),
-                                        attr.span,
-                                        E0779,
-                                        "target does not support `#[instruction_set]`"
-                                    )
-                                    .emit();
-                                    None
-                                } else if segments[1] == sym::a32 {
-                                    Some(InstructionSetAttr::ArmA32)
-                                } else if segments[1] == sym::t32 {
-                                    Some(InstructionSetAttr::ArmT32)
-                                } else {
-                                    unreachable!()
-                                }
-                            }
-                            _ => {
+            codegen_fn_attrs.instruction_set = attr.meta_item_list().and_then(|l| match &l[..] {
+                [NestedMetaItem::MetaItem(set)] => {
+                    let segments =
+                        set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
+                    match segments.as_slice() {
+                        [sym::arm, sym::a32] | [sym::arm, sym::t32] => {
+                            if !tcx.sess.target.has_thumb_interworking {
                                 struct_span_err!(
                                     tcx.sess.diagnostic(),
                                     attr.span,
                                     E0779,
-                                    "invalid instruction set specified",
+                                    "target does not support `#[instruction_set]`"
                                 )
                                 .emit();
                                 None
+                            } else if segments[1] == sym::a32 {
+                                Some(InstructionSetAttr::ArmA32)
+                            } else if segments[1] == sym::t32 {
+                                Some(InstructionSetAttr::ArmT32)
+                            } else {
+                                unreachable!()
                             }
                         }
+                        _ => {
+                            struct_span_err!(
+                                tcx.sess.diagnostic(),
+                                attr.span,
+                                E0779,
+                                "invalid instruction set specified",
+                            )
+                            .emit();
+                            None
+                        }
                     }
-                    [] => {
-                        struct_span_err!(
-                            tcx.sess.diagnostic(),
-                            attr.span,
-                            E0778,
-                            "`#[instruction_set]` requires an argument"
-                        )
-                        .emit();
-                        None
-                    }
-                    _ => {
-                        struct_span_err!(
-                            tcx.sess.diagnostic(),
-                            attr.span,
-                            E0779,
-                            "cannot specify more than one instruction set"
-                        )
-                        .emit();
-                        None
-                    }
-                },
-                _ => {
+                }
+                [] => {
                     struct_span_err!(
                         tcx.sess.diagnostic(),
                         attr.span,
                         E0778,
-                        "must specify an instruction set"
+                        "`#[instruction_set]` requires an argument"
                     )
                     .emit();
                     None
                 }
-            };
+                _ => {
+                    struct_span_err!(
+                        tcx.sess.diagnostic(),
+                        attr.span,
+                        E0779,
+                        "cannot specify more than one instruction set"
+                    )
+                    .emit();
+                    None
+                }
+            })
         } else if attr.has_name(sym::repr) {
             codegen_fn_attrs.alignment = match attr.meta_item_list() {
                 Some(items) => match items.as_slice() {
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" }
index b2c847d3fd8dd6fca2403ecd5d9216ae4c5e63f4..fc8e0c67ae09a0ec4b8d22aa8c9d5c9608a27854 100644 (file)
@@ -126,7 +126,7 @@ pub fn cast(
                     let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?;
                     let vtable = Scalar::from_maybe_pointer(vtable, self);
                     let data = self.read_immediate(src)?.to_scalar();
-                    let _assert_pointer_sized = data.to_pointer(self)?;
+                    let _assert_pointer_like = data.to_pointer(self)?;
                     let val = Immediate::ScalarPair(data, vtable);
                     self.write_immediate(val, dest)?;
                 } else {
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 954e84c303b83d031cc4b2be76c56b4e90e1cea1..7fab8954cb19f1911ff8654061770315bbf0e0a7 100644 (file)
@@ -11,6 +11,7 @@
 #![feature(associated_type_bounds)]
 #![feature(auto_traits)]
 #![feature(cell_leak)]
+#![feature(core_intrinsics)]
 #![feature(extend_one)]
 #![feature(hash_raw_entry)]
 #![feature(hasher_prefixfree_extras)]
index 393f173908128457c7f70f01c8eddbbc8240c7cf..3aca03f6e5c63cbae99bda4e58c09b05cddcf065 100644 (file)
@@ -88,6 +88,7 @@
 use std::collections::hash_map::Entry;
 use std::error::Error;
 use std::fs;
+use std::intrinsics::unlikely;
 use std::path::Path;
 use std::process;
 use std::sync::Arc;
@@ -395,11 +396,18 @@ pub fn query_provider(&self) -> TimingGuard<'_> {
     /// Record a query in-memory cache hit.
     #[inline(always)]
     pub fn query_cache_hit(&self, query_invocation_id: QueryInvocationId) {
-        self.instant_query_event(
-            |profiler| profiler.query_cache_hit_event_kind,
-            query_invocation_id,
-            EventFilter::QUERY_CACHE_HITS,
-        );
+        #[inline(never)]
+        #[cold]
+        fn cold_call(profiler_ref: &SelfProfilerRef, query_invocation_id: QueryInvocationId) {
+            profiler_ref.instant_query_event(
+                |profiler| profiler.query_cache_hit_event_kind,
+                query_invocation_id,
+            );
+        }
+
+        if unlikely(self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)) {
+            cold_call(self, query_invocation_id);
+        }
     }
 
     /// Start profiling a query being blocked on a concurrent execution.
@@ -444,20 +452,15 @@ fn instant_query_event(
         &self,
         event_kind: fn(&SelfProfiler) -> StringId,
         query_invocation_id: QueryInvocationId,
-        event_filter: EventFilter,
     ) {
-        drop(self.exec(event_filter, |profiler| {
-            let event_id = StringId::new_virtual(query_invocation_id.0);
-            let thread_id = get_thread_id();
-
-            profiler.profiler.record_instant_event(
-                event_kind(profiler),
-                EventId::from_virtual(event_id),
-                thread_id,
-            );
-
-            TimingGuard::none()
-        }));
+        let event_id = StringId::new_virtual(query_invocation_id.0);
+        let thread_id = get_thread_id();
+        let profiler = self.profiler.as_ref().unwrap();
+        profiler.profiler.record_instant_event(
+            event_kind(profiler),
+            EventId::from_virtual(event_id),
+            thread_id,
+        );
     }
 
     pub fn with_profiler(&self, f: impl FnOnce(&SelfProfiler)) {
index ed5341c40ef08b70ee2fae389ad86b949f80ba8b..ad71dcdf9d95384421a94cf71d35277e8dde8b03 100644 (file)
@@ -31,8 +31,8 @@
         pub auto trait Send {}
         pub auto trait Sync {}
 
-        impl<T: ?Sized> Send for T {}
-        impl<T: ?Sized> Sync for T {}
+        impl<T> Send for T {}
+        impl<T> Sync for T {}
 
         #[macro_export]
         macro_rules! rustc_erase_owner {
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..a392d70
--- /dev/null
@@ -0,0 +1,1351 @@
+//! 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>()
+    {
+        handler.emit_err(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 ca72b7faa9289b64f3f069e6adb0c07265347b8c..05ac8db0db88f893d64604f50fd86de7fa542026 100644 (file)
@@ -57,3 +57,9 @@ hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` la
 
 hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
     .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
+
+hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
+hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
+hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
+
+hir_typeck_convert_to_str = try converting the passed type into a `&str`
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 1728ef70cba0a7bd817b4db0a917b9060587c9db..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
 
@@ -203,8 +206,9 @@ parse_inclusive_range_extra_equals = unexpected `=` after inclusive range
     .suggestion_remove_eq = use `..=` instead
     .note = inclusive ranges end with a single equals sign (`..=`)
 
-parse_inclusive_range_match_arrow = unexpected `=>` after open range
-    .suggestion_add_space = add a space between the pattern and `=>`
+parse_inclusive_range_match_arrow = unexpected `>` after inclusive range
+    .label = this is parsed as an inclusive range `..=`
+    .suggestion = add a space between the pattern and `=>`
 
 parse_inclusive_range_no_end = inclusive range with no end
     .suggestion_open_range = use `..` instead
@@ -390,3 +394,194 @@ parse_where_clause_before_tuple_struct_body = where clauses are not allowed befo
     .name_label = while parsing this tuple struct
     .body_label = the struct body
     .suggestion = move the body before the where clause
+
+parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
+    .label = to use `async fn`, switch to Rust 2018 or later
+
+parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later
+
+parse_self_argument_pointer = cannot pass `self` by raw pointer
+    .label = cannot pass `self` by raw pointer
+
+parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by an item
+    .label = the visibility
+    .help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}`
+
+parse_default_not_followed_by_item = `default` is not followed by an item
+    .label = the `default` qualifier
+    .note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
+
+parse_missing_struct_for_struct_definition = missing `struct` for struct definition
+    .suggestion = add `struct` here to parse `{$ident}` as a public struct
+
+parse_missing_fn_for_function_definition = missing `fn` for function definition
+    .suggestion = add `fn` here to parse `{$ident}` as a public function
+
+parse_missing_fn_for_method_definition = missing `fn` for method definition
+    .suggestion = add `fn` here to parse `{$ident}` as a public method
+
+parse_ambiguous_missing_keyword_for_item_definition = missing `fn` or `struct` for function or struct definition
+    .suggestion = if you meant to call a macro, try
+    .help = if you meant to call a macro, remove the `pub` and add a trailing `!` after the identifier
+
+parse_missing_trait_in_trait_impl = missing trait in a trait impl
+    .suggestion_add_trait = add a trait here
+    .suggestion_remove_for = for an inherent impl, drop this `for`
+
+parse_missing_for_in_trait_impl = missing `for` in a trait impl
+    .suggestion = add `for` here
+
+parse_expected_trait_in_trait_impl_found_type = expected a trait, found type
+
+parse_non_item_in_item_list = non-item in item list
+    .suggestion_use_const_not_let = consider using `const` instead of `let` for associated const
+    .label_list_start = item list starts here
+    .label_non_item = non-item starts here
+    .label_list_end = item list ends here
+    .suggestion_remove_semicolon = consider removing this semicolon
+
+parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases
+
+parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto`
+parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe`
+
+parse_associated_static_item_not_allowed = associated `static` items are not allowed
+
+parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements
+    .label = dash-separated idents are not valid
+    .suggestion = if the original crate name uses dashes you need to use underscores in the code
+
+parse_extern_item_cannot_be_const = extern items cannot be `const`
+    .suggestion = try using a static value
+    .note = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+parse_const_global_cannot_be_mutable = const globals cannot be mutable
+    .label = cannot be mutable
+    .suggestion = you might want to declare a static instead
+
+parse_missing_const_type = missing type for `{$kind}` item
+    .suggestion = provide a type for the item
+
+parse_enum_struct_mutually_exclusive = `enum` and `struct` are mutually exclusive
+    .suggestion = replace `enum struct` with
+
+parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name
+parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}`
+parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}`
+parse_unexpected_token_after_struct_name_found_reserved_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved keyword `{$token}`
+parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}`
+parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}`
+
+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
+
+parse_nonterminal_expected_item_keyword = expected an item keyword
+parse_nonterminal_expected_statement = expected a statement
+parse_nonterminal_expected_ident = expected ident, found `{$token}`
+parse_nonterminal_expected_lifetime = expected a lifetime, found `{$token}`
+
+parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
+parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
+parse_sugg_remove_leading_vert_in_pattern = remove the `|`
+parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses
+
+parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
+
+parse_unexpected_vert_vert_before_function_parameter = unexpected `||` before function parameter
+    .suggestion = remove the `||`
+
+parse_label_while_parsing_or_pattern_here = while parsing this or-pattern starting here
+
+parse_unexpected_vert_vert_in_pattern = unexpected token `||` in pattern
+    .suggestion = use a single `|` to separate multiple alternative patterns
+
+parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern
+    .suggestion = remove the `{$token}`
+
+parse_dotdotdot_rest_pattern = unexpected `...`
+    .label = not a valid pattern
+    .suggestion = for a rest pattern, use `..` instead of `...`
+
+parse_pattern_on_wrong_side_of_at = pattern on wrong side of `@`
+    .label_pattern = pattern on the left, should be on the right
+    .label_binding = binding on the right, should be on the left
+    .suggestion = switch the order
+
+parse_expected_binding_left_of_at = left-hand side of `@` must be a binding
+    .label_lhs = interpreted as a pattern, not a binding
+    .label_rhs = also a pattern
+    .note = bindings are `x`, `mut x`, `ref x`, and `ref mut x`
+
+parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation
+    .suggestion = add parentheses to clarify the precedence
+
+parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in pattern
+    .suggestion = remove the lifetime
+
+parse_ref_mut_order_incorrect = the order of `mut` and `ref` is incorrect
+    .suggestion = try switching the order
+
+parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual binding
+    .suggestion = add `mut` to each binding
+parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding
+    .suggestion = remove the `mut` prefix
+parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable @ pattern`
+
+parse_repeated_mut_in_pattern = `mut` on a binding may not be repeated
+    .suggestion = remove the additional `mut`s
+
+parse_dot_dot_dot_range_to_pattern_not_allowed = range-to patterns with `...` are not allowed
+    .suggestion = use `..=` instead
+
+parse_enum_pattern_instead_of_identifier = expected identifier, found enum pattern
+
+parse_dot_dot_dot_for_remaining_fields = expected field pattern, found `{$token_str}`
+    .suggestion = to omit remaining fields, use `..`
+
+parse_expected_comma_after_pattern_field = expected `,`
+
+parse_return_types_use_thin_arrow = return types are denoted using `->`
+    .suggestion = use `->` instead
+
+parse_need_plus_after_trait_object_lifetime = lifetime in trait object type must be followed by `+`
+
+parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyword in raw pointer type
+    .suggestion = add `mut` or `const` here
+
+parse_lifetime_after_mut = lifetime must precede `mut`
+    .suggestion = place the lifetime before `mut`
+
+parse_dyn_after_mut = `mut` must precede `dyn`
+    .suggestion = place `mut` before `dyn`
+
+parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const`
+    .label = `const` because of this
+    .suggestion = remove the `const` qualifier
+
+parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async`
+    .label = `async` because of this
+    .suggestion = remove the `async` qualifier
+
+parse_nested_c_variadic_type = C-variadic type `...` may not be nested inside another type
+
+parse_invalid_dyn_keyword = invalid `dyn` keyword
+    .help = `dyn` is only needed at the start of a trait `+`-separated list
+    .suggestion = remove this keyword
+
+parse_negative_bounds_not_supported = negative bounds are not supported
+    .label = negative bounds are not supported
+    .suggestion = {$num_bounds ->
+            [one] remove the bound
+           *[other] remove the bounds
+        }
+
+parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
+parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
+parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
index 6ebb188288f0016e604ebfcd3b1ce207fdc2e14c..0c7e02912d4ef5af76dd39e631a5c3d32de306aa 100644 (file)
@@ -182,6 +182,18 @@ passes_has_incoherent_inherent_impl =
     `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits.
     .label = only adts, extern types and traits are supported
 
+passes_both_ffi_const_and_pure =
+    `#[ffi_const]` function cannot be `#[ffi_pure]`
+
+passes_ffi_pure_invalid_target =
+    `#[ffi_pure]` may only be used on foreign functions
+
+passes_ffi_const_invalid_target =
+    `#[ffi_const]` may only be used on foreign functions
+
+passes_ffi_returns_twice_invalid_target =
+    `#[ffi_returns_twice]` may only be used on foreign functions
+
 passes_must_use_async =
     `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within
     .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use`
index df949e46fbde507e9bdeee514e4d979fca56c7de..9ed8ab67431c05b9a51a9bb4fa1f6310b0e2050d 100644 (file)
@@ -7,7 +7,6 @@
 use rustc_error_messages::fluent_value_from_str_list_sep_by_and;
 use rustc_error_messages::FluentValue;
 use rustc_lint_defs::{Applicability, LintExpectationId};
-use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
 use std::borrow::Cow;
@@ -555,18 +554,6 @@ pub fn span_help<S: Into<MultiSpan>>(
         self
     }
 
-    /// Help the user upgrade to the latest edition.
-    /// This is factored out to make sure it does the right thing with `Cargo.toml`.
-    pub fn help_use_latest_edition(&mut self) -> &mut Self {
-        if std::env::var_os("CARGO").is_some() {
-            self.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
-        } else {
-            self.help(&format!("pass `--edition {}` to `rustc`", LATEST_STABLE_EDITION));
-        }
-        self.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
-        self
-    }
-
     /// Disallow attaching suggestions this diagnostic.
     /// Any suggestions attached e.g. with the `span_suggestion_*` methods
     /// (before and after the call to `disable_suggestions`) will be ignored.
index c9d662ad43fe50ed08359748f921deec6c1e11e0..3064d2bedbe125ffac7985e43a20f2b2ad29741c 100644 (file)
@@ -669,7 +669,6 @@ pub fn span_labels(
         sp: impl Into<MultiSpan>,
         msg: impl Into<SubdiagnosticMessage>,
     ) -> &mut Self);
-    forward!(pub fn help_use_latest_edition(&mut self,) -> &mut Self);
     forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
 
     forward!(pub fn disable_suggestions(&mut self,) -> &mut Self);
index 7a94ce3777a29c8337b3439a50ce8e376ddc3cb6..5ada85d04b0bcb60556600353b5e492f118588a2 100644 (file)
@@ -189,6 +189,14 @@ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
     }
 }
 
+impl IntoDiagnosticArg for ast::Visibility {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        let s = pprust::vis_to_string(&self);
+        let s = s.trim_end().to_string();
+        DiagnosticArgValue::Str(Cow::Owned(s))
+    }
+}
+
 impl IntoDiagnosticArg for Level {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
         DiagnosticArgValue::Str(Cow::Borrowed(self.to_cmd_flag()))
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 9b16e79d49a9e951042e6978f33e92d712195430..b4c12651e7a2d36e7011fac4664f36d63f695c05 100644 (file)
@@ -131,10 +131,14 @@ pub fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef {
         }
     }
 
-    pub fn trait_bound(&self, path: ast::Path) -> ast::GenericBound {
+    pub fn trait_bound(&self, path: ast::Path, is_const: bool) -> ast::GenericBound {
         ast::GenericBound::Trait(
             self.poly_trait_ref(path.span, path),
-            ast::TraitBoundModifier::None,
+            if is_const {
+                ast::TraitBoundModifier::MaybeConst
+            } else {
+                ast::TraitBoundModifier::None
+            },
         )
     }
 
@@ -272,6 +276,10 @@ pub fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
         self.expr(sp, ast::ExprKind::AddrOf(ast::BorrowKind::Ref, ast::Mutability::Not, e))
     }
 
+    pub fn expr_paren(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
+        self.expr(sp, ast::ExprKind::Paren(e))
+    }
+
     pub fn expr_call(
         &self,
         span: Span,
index 99fe474541e9d03b72fad276e2b0e6fd163391d3..de34df0114a743c2f89327d94c2cd7f13fbad9a9 100644 (file)
@@ -1,5 +1,5 @@
 use rustc_ast::token::{self, Delimiter};
-use rustc_ast::tokenstream::{CursorRef, TokenStream, TokenTree};
+use rustc_ast::tokenstream::{RefTokenTreeCursor, TokenStream, TokenTree};
 use rustc_ast::{LitIntType, LitKind};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, PResult};
@@ -72,7 +72,7 @@ pub(crate) fn ident(&self) -> Option<Ident> {
 
 // Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}`
 fn check_trailing_token<'sess>(
-    iter: &mut CursorRef<'_>,
+    iter: &mut RefTokenTreeCursor<'_>,
     sess: &'sess ParseSess,
 ) -> PResult<'sess, ()> {
     if let Some(tt) = iter.next() {
@@ -88,7 +88,7 @@ fn check_trailing_token<'sess>(
 
 /// Parse a meta-variable `count` expression: `count(ident[, depth])`
 fn parse_count<'sess>(
-    iter: &mut CursorRef<'_>,
+    iter: &mut RefTokenTreeCursor<'_>,
     sess: &'sess ParseSess,
     span: Span,
 ) -> PResult<'sess, MetaVarExpr> {
@@ -99,7 +99,7 @@ fn parse_count<'sess>(
 
 /// Parses the depth used by index(depth) and length(depth).
 fn parse_depth<'sess>(
-    iter: &mut CursorRef<'_>,
+    iter: &mut RefTokenTreeCursor<'_>,
     sess: &'sess ParseSess,
     span: Span,
 ) -> PResult<'sess, usize> {
@@ -126,7 +126,7 @@ fn parse_depth<'sess>(
 
 /// Parses an generic ident
 fn parse_ident<'sess>(
-    iter: &mut CursorRef<'_>,
+    iter: &mut RefTokenTreeCursor<'_>,
     sess: &'sess ParseSess,
     span: Span,
 ) -> PResult<'sess, Ident> {
@@ -152,7 +152,7 @@ fn parse_ident<'sess>(
 
 /// Tries to move the iterator forward returning `true` if there is a comma. If not, then the
 /// iterator is not modified and the result is `false`.
-fn try_eat_comma(iter: &mut CursorRef<'_>) -> bool {
+fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool {
     if let Some(TokenTree::Token(token::Token { kind: token::Comma, .. }, _)) = iter.look_ahead(0) {
         let _ = iter.next();
         return true;
index 9158fc082471f8fbedaf7e915fa998d83243215d..0454633091568ea61c5de649f85d8b206d79b019 100644 (file)
@@ -287,7 +287,7 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     TryTraitBranch,          sym::branch,              branch_fn,                  Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
     TryTraitFromYeet,        sym::from_yeet,           from_yeet_fn,               Target::Fn,             GenericRequirement::None;
 
-    PointerSized,            sym::pointer_sized,       pointer_sized,              Target::Trait,          GenericRequirement::Exact(0);
+    PointerLike,             sym::pointer_like,        pointer_like,               Target::Trait,          GenericRequirement::Exact(0);
 
     Poll,                    sym::Poll,                poll,                       Target::Enum,           GenericRequirement::None;
     PollReady,               sym::Ready,               poll_ready_variant,         Target::Variant,        GenericRequirement::None;
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 21e700418105047a8a52540a41a85c7b26e140b1..236e36f28ca474e5261a54a0b2565149811179d6 100644 (file)
@@ -246,7 +246,7 @@ fn compare_method_predicate_entailment<'tcx>(
 
     let mut wf_tys = FxIndexSet::default();
 
-    let unnormalized_impl_sig = infcx.replace_bound_vars_with_fresh_vars(
+    let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars(
         impl_m_span,
         infer::HigherRankedType,
         tcx.fn_sig(impl_m.def_id).subst_identity(),
@@ -640,7 +640,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     let impl_sig = ocx.normalize(
         &norm_cause,
         param_env,
-        infcx.replace_bound_vars_with_fresh_vars(
+        infcx.instantiate_binder_with_fresh_vars(
             return_span,
             infer::HigherRankedType,
             tcx.fn_sig(impl_m.def_id).subst_identity(),
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 95b03eb8263fda2031504dd4ef6a22319b31b23a..7d381d8902ac2f10ee913ac96fe7c98ec0d01613 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::IgnoreRegions;
 use rustc_middle::ty::{
-    self, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+    self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 use rustc_session::lint;
 use rustc_span::def_id::{DefId, LocalDefId};
@@ -86,7 +86,7 @@ fn do_orphan_check_impl<'tcx>(
     // struct B { }
     // impl Foo for A { }
     // impl Foo for B { }
-    // impl !Send for (A, B) { }
+    // impl !Foo for (A, B) { }
     // ```
     //
     // This final impl is legal according to the orphan
@@ -99,50 +99,193 @@ fn do_orphan_check_impl<'tcx>(
         tcx.trait_is_auto(trait_def_id)
     );
 
-    if tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
+    if tcx.trait_is_auto(trait_def_id) {
         let self_ty = trait_ref.self_ty();
-        let opt_self_def_id = match *self_ty.kind() {
-            ty::Adt(self_def, _) => Some(self_def.did()),
-            ty::Foreign(did) => Some(did),
-            _ => None,
-        };
 
-        let msg = match opt_self_def_id {
-            // We only want to permit nominal types, but not *all* nominal types.
-            // They must be local to the current crate, so that people
-            // can't do `unsafe impl Send for Rc<SomethingLocal>` or
-            // `impl !Send for Box<SomethingLocalAndSend>`.
-            Some(self_def_id) => {
-                if self_def_id.is_local() {
-                    None
+        // If the impl is in the same crate as the auto-trait, almost anything
+        // goes.
+        //
+        //     impl MyAuto for Rc<Something> {}  // okay
+        //     impl<T> !MyAuto for *const T {}   // okay
+        //     impl<T> MyAuto for T {}           // okay
+        //
+        // But there is one important exception: implementing for a trait object
+        // is not allowed.
+        //
+        //     impl MyAuto for dyn Trait {}      // NOT OKAY
+        //     impl<T: ?Sized> MyAuto for T {}   // NOT OKAY
+        //
+        // With this restriction, it's guaranteed that an auto-trait is
+        // implemented for a trait object if and only if the auto-trait is one
+        // of the trait object's trait bounds (or a supertrait of a bound). In
+        // other words `dyn Trait + AutoTrait` always implements AutoTrait,
+        // while `dyn Trait` never implements AutoTrait.
+        //
+        // This is necessary in order for autotrait bounds on methods of trait
+        // objects to be sound.
+        //
+        //     auto trait AutoTrait {}
+        //
+        //     trait ObjectSafeTrait {
+        //         fn f(&self) where Self: AutoTrait;
+        //     }
+        //
+        // We can allow f to be called on `dyn ObjectSafeTrait + AutoTrait`.
+        //
+        // If we didn't deny `impl AutoTrait for dyn Trait`, it would be unsound
+        // for the ObjectSafeTrait shown above to be object safe because someone
+        // could take some type implementing ObjectSafeTrait but not AutoTrait,
+        // unsize it to `dyn ObjectSafeTrait`, and call .f() which has no
+        // concrete implementation (issue #50781).
+        enum LocalImpl {
+            Allow,
+            Disallow { problematic_kind: &'static str },
+        }
+
+        // If the auto-trait is from a dependency, it must only be getting
+        // implemented for a nominal type, and specifically one local to the
+        // current crate.
+        //
+        //     impl<T> Sync for MyStruct<T> {}   // okay
+        //
+        //     impl Sync for Rc<MyStruct> {}     // NOT OKAY
+        enum NonlocalImpl {
+            Allow,
+            DisallowBecauseNonlocal,
+            DisallowOther,
+        }
+
+        // Exhaustive match considering that this logic is essential for
+        // soundness.
+        let (local_impl, nonlocal_impl) = match self_ty.kind() {
+            // struct Struct<T>;
+            // impl AutoTrait for Struct<Foo> {}
+            ty::Adt(self_def, _) => (
+                LocalImpl::Allow,
+                if self_def.did().is_local() {
+                    NonlocalImpl::Allow
+                } else {
+                    NonlocalImpl::DisallowBecauseNonlocal
+                },
+            ),
+
+            // extern { type OpaqueType; }
+            // impl AutoTrait for OpaqueType {}
+            ty::Foreign(did) => (
+                LocalImpl::Allow,
+                if did.is_local() {
+                    NonlocalImpl::Allow
                 } else {
-                    Some((
-                        format!(
-                            "cross-crate traits with a default impl, like `{}`, \
-                                    can only be implemented for a struct/enum type \
-                                    defined in the current crate",
-                            tcx.def_path_str(trait_def_id)
-                        ),
-                        "can't implement cross-crate trait for type in another crate",
-                    ))
+                    NonlocalImpl::DisallowBecauseNonlocal
+                },
+            ),
+
+            // impl AutoTrait for dyn Trait {}
+            ty::Dynamic(..) => (
+                LocalImpl::Disallow { problematic_kind: "trait object" },
+                NonlocalImpl::DisallowOther,
+            ),
+
+            // impl<T> AutoTrait for T {}
+            // impl<T: ?Sized> AutoTrait for T {}
+            ty::Param(..) => (
+                if self_ty.is_sized(tcx, tcx.param_env(def_id)) {
+                    LocalImpl::Allow
+                } else {
+                    LocalImpl::Disallow { problematic_kind: "generic type" }
+                },
+                NonlocalImpl::DisallowOther,
+            ),
+
+            // trait Id { type This: ?Sized; }
+            // impl<T: ?Sized> Id for T {
+            //     type This = T;
+            // }
+            // impl<T: ?Sized> AutoTrait for <T as Id>::This {}
+            ty::Alias(AliasKind::Projection, _) => (
+                LocalImpl::Disallow { problematic_kind: "associated type" },
+                NonlocalImpl::DisallowOther,
+            ),
+
+            // type Opaque = impl Trait;
+            // impl AutoTrait for Opaque {}
+            ty::Alias(AliasKind::Opaque, _) => (
+                LocalImpl::Disallow { problematic_kind: "opaque type" },
+                NonlocalImpl::DisallowOther,
+            ),
+
+            ty::Bool
+            | ty::Char
+            | ty::Int(..)
+            | ty::Uint(..)
+            | ty::Float(..)
+            | ty::Str
+            | ty::Array(..)
+            | ty::Slice(..)
+            | ty::RawPtr(..)
+            | ty::Ref(..)
+            | ty::FnDef(..)
+            | ty::FnPtr(..)
+            | ty::Never
+            | ty::Tuple(..) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),
+
+            ty::Closure(..)
+            | ty::Generator(..)
+            | ty::GeneratorWitness(..)
+            | ty::GeneratorWitnessMIR(..)
+            | ty::Bound(..)
+            | ty::Placeholder(..)
+            | ty::Infer(..) => span_bug!(sp, "weird self type for autotrait impl"),
+
+            ty::Error(..) => (LocalImpl::Allow, NonlocalImpl::Allow),
+        };
+
+        if trait_def_id.is_local() {
+            match local_impl {
+                LocalImpl::Allow => {}
+                LocalImpl::Disallow { problematic_kind } => {
+                    let msg = format!(
+                        "traits with a default impl, like `{trait}`, \
+                                cannot be implemented for {problematic_kind} `{self_ty}`",
+                        trait = tcx.def_path_str(trait_def_id),
+                    );
+                    let label = format!(
+                        "a trait object implements `{trait}` if and only if `{trait}` \
+                                is one of the trait object's trait bounds",
+                        trait = tcx.def_path_str(trait_def_id),
+                    );
+                    let reported =
+                        struct_span_err!(tcx.sess, sp, E0321, "{}", msg).note(label).emit();
+                    return Err(reported);
                 }
             }
-            _ => Some((
-                format!(
-                    "cross-crate traits with a default impl, like `{}`, can \
+        } else {
+            if let Some((msg, label)) = match nonlocal_impl {
+                NonlocalImpl::Allow => None,
+                NonlocalImpl::DisallowBecauseNonlocal => Some((
+                    format!(
+                        "cross-crate traits with a default impl, like `{}`, \
+                                can only be implemented for a struct/enum type \
+                                defined in the current crate",
+                        tcx.def_path_str(trait_def_id)
+                    ),
+                    "can't implement cross-crate trait for type in another crate",
+                )),
+                NonlocalImpl::DisallowOther => Some((
+                    format!(
+                        "cross-crate traits with a default impl, like `{}`, can \
                                 only be implemented for a struct/enum type, not `{}`",
-                    tcx.def_path_str(trait_def_id),
-                    self_ty
-                ),
-                "can't implement cross-crate trait with a default impl for \
-                        non-struct/enum type",
-            )),
-        };
-
-        if let Some((msg, label)) = msg {
-            let reported =
-                struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
-            return Err(reported);
+                        tcx.def_path_str(trait_def_id),
+                        self_ty
+                    ),
+                    "can't implement cross-crate trait with a default impl for \
+                            non-struct/enum type",
+                )),
+            } {
+                let reported =
+                    struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
+                return Err(reported);
+            }
         }
     }
 
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 c220956a2012e15620f124c86c5942b479587759..089863a66e73be9843af6ea4a5f42098aeb81edf 100644 (file)
@@ -156,7 +156,7 @@ fn try_overloaded_call_step(
                 // fnmut vs fnonce. If so, we have to defer further processing.
                 if self.closure_kind(substs).is_none() {
                     let closure_sig = substs.as_closure().sig();
-                    let closure_sig = self.replace_bound_vars_with_fresh_vars(
+                    let closure_sig = self.instantiate_binder_with_fresh_vars(
                         call_expr.span,
                         infer::FnCall,
                         closure_sig,
@@ -437,7 +437,7 @@ fn confirm_builtin_call(
         // renormalize the associated types at this point, since they
         // previously appeared within a `Binder<>` and hence would not
         // have been normalized before.
-        let fn_sig = self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig);
+        let fn_sig = self.instantiate_binder_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig);
         let fn_sig = self.normalize(call_expr.span, fn_sig);
 
         // Call the generic checker.
index 329b69eff54a396338f6e6f4e58e69f0ffc3c61c..211fe477a2d8d77bd77890602796e55bfe103a80 100644 (file)
@@ -15,6 +15,7 @@
 use rustc_middle::ty::{self, Ty, TypeSuperVisitable, TypeVisitor};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
+use rustc_span::sym;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::ArgKind;
@@ -288,21 +289,20 @@ fn deduce_sig_from_projection(
         let trait_def_id = projection.trait_def_id(tcx);
 
         let is_fn = tcx.is_fn_trait(trait_def_id);
-        let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
-        let is_gen = gen_trait == trait_def_id;
+
+        let gen_trait = tcx.lang_items().gen_trait();
+        let is_gen = gen_trait == Some(trait_def_id);
+
         if !is_fn && !is_gen {
             debug!("not fn or generator");
             return None;
         }
 
-        if is_gen {
-            // Check that we deduce the signature from the `<_ as std::ops::Generator>::Return`
-            // associated item and not yield.
-            let return_assoc_item = self.tcx.associated_item_def_ids(gen_trait)[1];
-            if return_assoc_item != projection.projection_def_id() {
-                debug!("not return assoc item of generator");
-                return None;
-            }
+        // Check that we deduce the signature from the `<_ as std::ops::Generator>::Return`
+        // associated item and not yield.
+        if is_gen && self.tcx.associated_item(projection.projection_def_id()).name != sym::Return {
+            debug!("not `Return` assoc item of `Generator`");
+            return None;
         }
 
         let input_tys = if is_fn {
@@ -544,7 +544,7 @@ fn merge_supplied_sig_with_expectation(
             )
             .map(|(hir_ty, &supplied_ty)| {
                 // Instantiate (this part of..) S to S', i.e., with fresh variables.
-                self.replace_bound_vars_with_fresh_vars(
+                self.instantiate_binder_with_fresh_vars(
                     hir_ty.span,
                     LateBoundRegionConversionTime::FnCall,
                     // (*) binder moved to here
@@ -566,7 +566,7 @@ fn merge_supplied_sig_with_expectation(
                 all_obligations.extend(obligations);
             }
 
-            let supplied_output_ty = self.replace_bound_vars_with_fresh_vars(
+            let supplied_output_ty = self.instantiate_binder_with_fresh_vars(
                 decl.output.span(),
                 LateBoundRegionConversionTime::FnCall,
                 supplied_sig.output(),
index ade9c037c519405d04470edbf8c5741f8e9cba07..7173239ba619a849b0e71a46e49ed3395dde162e 100644 (file)
@@ -765,7 +765,7 @@ fn coerce_dyn_star(
             self.cause.clone(),
             self.param_env,
             ty::Binder::dummy(
-                self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerSized, [a]),
+                self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerLike, [a]),
             ),
         ));
 
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 5b4fd5e4a5283833b8eaa051df969a021e165161..2c8979402b654b8fb5f7cdb57d07d6208d42f29f 100644 (file)
@@ -2,7 +2,11 @@
 use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, MultiSpan, SubdiagnosticMessage};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_middle::ty::Ty;
-use rustc_span::{symbol::Ident, Span};
+use rustc_span::{
+    edition::{Edition, LATEST_STABLE_EDITION},
+    symbol::Ident,
+    Span,
+};
 
 #[derive(Diagnostic)]
 #[diag(hir_typeck_field_multiply_specified_in_initializer, code = "E0062")]
@@ -205,3 +209,24 @@ pub struct LangStartIncorrectRetTy<'tcx> {
     pub expected_ty: Ty<'tcx>,
     pub found_ty: Ty<'tcx>,
 }
+
+#[derive(Subdiagnostic)]
+pub enum HelpUseLatestEdition {
+    #[help(hir_typeck_help_set_edition_cargo)]
+    #[note(hir_typeck_note_edition_guide)]
+    Cargo { edition: Edition },
+    #[help(hir_typeck_help_set_edition_standalone)]
+    #[note(hir_typeck_note_edition_guide)]
+    Standalone { edition: Edition },
+}
+
+impl HelpUseLatestEdition {
+    pub fn new() -> Self {
+        let edition = LATEST_STABLE_EDITION;
+        if std::env::var_os("CARGO").is_some() {
+            Self::Cargo { edition }
+        } else {
+            Self::Standalone { edition }
+        }
+    }
+}
index 74913bac72411a7b73d771648c088367fc541db5..bb235a4836153aedb9883677474e83942bdda263 100644 (file)
@@ -8,7 +8,7 @@
 use crate::errors::TypeMismatchFruTypo;
 use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
 use crate::errors::{
-    FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
+    FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition,
     YieldExprOutsideOfGenerator,
 };
 use crate::fatally_break_rust;
@@ -23,8 +23,8 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{
-    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
-    ErrorGuaranteed, StashKey,
+    pluralize, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder,
+    DiagnosticId, ErrorGuaranteed, StashKey,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -568,7 +568,7 @@ pub(crate) fn check_expr_path(
                     // placeholder lifetimes with probing, we just replace higher lifetimes
                     // with fresh vars.
                     let span = args.get(i).map(|a| a.span).unwrap_or(expr.span);
-                    let input = self.replace_bound_vars_with_fresh_vars(
+                    let input = self.instantiate_binder_with_fresh_vars(
                         span,
                         infer::LateBoundRegionConversionTime::FnCall,
                         fn_sig.input(i),
@@ -586,7 +586,7 @@ pub(crate) fn check_expr_path(
             // Also, as we just want to check sizedness, instead of introducing
             // placeholder lifetimes with probing, we just replace higher lifetimes
             // with fresh vars.
-            let output = self.replace_bound_vars_with_fresh_vars(
+            let output = self.instantiate_binder_with_fresh_vars(
                 expr.span,
                 infer::LateBoundRegionConversionTime::FnCall,
                 fn_sig.output(),
@@ -2433,7 +2433,7 @@ fn ban_nonexisting_field(
             // We know by construction that `<expr>.await` is either on Rust 2015
             // or results in `ExprKind::Await`. Suggest switching the edition to 2018.
             err.note("to `.await` a `Future`, switch to Rust 2018 or later");
-            err.help_use_latest_edition();
+            HelpUseLatestEdition::new().add_to_diagnostic(&mut err);
         }
 
         err.emit();
index a355a54d6959abb5570144e9c40b53f2e973ce3f..e84b3de124c58070388d3b741de2630569a215ff 100644 (file)
@@ -454,8 +454,7 @@ pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
             None if let Some(e) = self.tainted_by_errors() => self.tcx.ty_error_with_guaranteed(e),
             None => {
                 bug!(
-                    "no type for node {}: {} in fcx {}",
-                    id,
+                    "no type for node {} in fcx {}",
                     self.tcx.hir().node_to_string(id),
                     self.tag()
                 );
@@ -922,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..3814ddaf73f44b8e64ebeb89418f1c875dc1da16 100644 (file)
@@ -1,4 +1,5 @@
 mod _impl;
+mod adjust_fulfillment_errors;
 mod arg_matrix;
 mod checks;
 mod suggestions;
@@ -288,7 +289,7 @@ fn projected_ty_from_poly_trait_ref(
         item_segment: &hir::PathSegment<'_>,
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Ty<'tcx> {
-        let trait_ref = self.replace_bound_vars_with_fresh_vars(
+        let trait_ref = self.instantiate_binder_with_fresh_vars(
             span,
             infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
             poly_trait_ref,
index 6046e55c65c18366c2b2cb10fae1cd1a390fe7f1..eaad57d8c2e9f1088ab839e4e266d62b302ea743 100644 (file)
@@ -3,7 +3,7 @@
 use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
 use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
 use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
-use rustc_errors::{Applicability, Diagnostic, MultiSpan};
+use rustc_errors::{fluent, Applicability, Diagnostic, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind};
 use rustc_hir::lang_items::LangItem;
@@ -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,
@@ -414,11 +415,16 @@ pub fn suggest_deref_ref_or_into(
                 if let ty::Adt(adt, _) = peeled.kind()
                     && Some(adt.did()) == self.tcx.lang_items().string()
                 {
+                    let sugg = if ref_cnt == 0 {
+                        ".as_deref()"
+                    } else {
+                        ".map(|x| x.as_str())"
+                    };
                     err.span_suggestion_verbose(
                         expr.span.shrink_to_hi(),
-                        "try converting the passed type into a `&str`",
-                        format!(".map(|x| &*{}x)", "*".repeat(ref_cnt)),
-                        Applicability::MaybeIncorrect,
+                        fluent::hir_typeck_convert_to_str,
+                        sugg,
+                        Applicability::MachineApplicable,
                     );
                     return true;
                 }
@@ -682,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()
@@ -699,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);
@@ -1239,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,
@@ -1259,16 +1336,17 @@ pub(crate) fn suggest_associated_const(
                 hir::Path { segments: [segment], .. },
             ))
             | hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => {
-                let self_ty = self.astconv().ast_ty_to_ty(ty);
-                if let Ok(pick) = self.probe_for_name(
-                    Mode::Path,
-                    Ident::new(capitalized_name, segment.ident.span),
-                    Some(expected_ty),
-                    IsSuggestion(true),
-                    self_ty,
-                    expr.hir_id,
-                    ProbeScope::TraitsInScope,
-                ) {
+                if let Some(self_ty) = self.typeck_results.borrow().node_type_opt(ty.hir_id)
+                    && let Ok(pick) = self.probe_for_name(
+                        Mode::Path,
+                        Ident::new(capitalized_name, segment.ident.span),
+                        Some(expected_ty),
+                        IsSuggestion(true),
+                        self_ty,
+                        expr.hir_id,
+                        ProbeScope::TraitsInScope,
+                    )
+                {
                     (pick.item, segment)
                 } else {
                     return false;
@@ -1380,6 +1458,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 48c75cde9a5fc544948e231ea4077a86ad698f9d..92240b66eb1d4727a4a6aaa9d6df41efa26b43ef 100644 (file)
@@ -155,8 +155,7 @@ fn resolve_type_vars_or_error(
             None if self.is_tainted_by_errors() => Err(()),
             None => {
                 bug!(
-                    "no type for node {}: {} in mem_categorization",
-                    id,
+                    "no type for node {} in mem_categorization",
                     self.tcx().hir().node_to_string(id)
                 );
             }
index 65ca47bfe538bbd5c42cb8854ee9dfa1adcc601b..fa0dc4d84150636f57bcebd7014b102d8bd57596 100644 (file)
@@ -262,7 +262,7 @@ fn fresh_receiver_substs(
                     let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty);
                     let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id);
                     let upcast_trait_ref =
-                        this.replace_bound_vars_with_fresh_vars(upcast_poly_trait_ref);
+                        this.instantiate_binder_with_fresh_vars(upcast_poly_trait_ref);
                     debug!(
                         "original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
                         original_poly_trait_ref, upcast_trait_ref, trait_def_id
@@ -285,7 +285,7 @@ fn fresh_receiver_substs(
             probe::WhereClausePick(poly_trait_ref) => {
                 // Where clauses can have bound regions in them. We need to instantiate
                 // those to convert from a poly-trait-ref to a trait-ref.
-                self.replace_bound_vars_with_fresh_vars(poly_trait_ref).substs
+                self.instantiate_binder_with_fresh_vars(poly_trait_ref).substs
             }
         }
     }
@@ -506,7 +506,7 @@ fn instantiate_method_sig(
         let sig = self.tcx.fn_sig(def_id).subst(self.tcx, all_substs);
         debug!("type scheme substituted, sig={:?}", sig);
 
-        let sig = self.replace_bound_vars_with_fresh_vars(sig);
+        let sig = self.instantiate_binder_with_fresh_vars(sig);
         debug!("late-bound lifetimes from method instantiated, sig={:?}", sig);
 
         (sig, method_predicates)
@@ -625,10 +625,10 @@ fn upcast(
         upcast_trait_refs.into_iter().next().unwrap()
     }
 
-    fn replace_bound_vars_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T
+    fn instantiate_binder_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T
     where
         T: TypeFoldable<'tcx> + Copy,
     {
-        self.fcx.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, value)
+        self.fcx.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, value)
     }
 }
index 60d4dc326eea16f837983767fc138d6ffda50a5d..d5d10cf272afad674cced63f4473b4c934562a5b 100644 (file)
@@ -401,7 +401,7 @@ fn construct_obligation_for_trait(
         // with bound regions.
         let fn_sig = tcx.fn_sig(def_id).subst(self.tcx, substs);
         let fn_sig =
-            self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
+            self.instantiate_binder_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
 
         let InferOk { value, obligations: o } =
             self.at(&obligation.cause, self.param_env).normalize(fn_sig);
index 0b30bf957a3d3dba303edeb2da613d44411c84e6..4ce401b52bd269292890b3b9bd3da39132ef1825 100644 (file)
@@ -924,7 +924,7 @@ fn matches_return_type(
             ty::AssocKind::Fn => self.probe(|_| {
                 let substs = self.fresh_substs_for_item(self.span, method.def_id);
                 let fty = self.tcx.fn_sig(method.def_id).subst(self.tcx, substs);
-                let fty = self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty);
+                let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
 
                 if let Some(self_ty) = self_ty {
                     if self
@@ -1563,6 +1563,7 @@ fn consider_probe(
                                     traits::ImplDerivedObligationCause {
                                         derived,
                                         impl_def_id,
+                                        impl_def_predicate_index: None,
                                         span,
                                     },
                                 ))
index 78cea1f4d8d3e199295d83834e2e33398b5d2851..ba72aefe39c169f7472b3860dca791fe644b5e5d 100644 (file)
@@ -335,7 +335,9 @@ fn check_overloaded_binop(
                                 format!("cannot divide `{lhs_ty}` by `{rhs_ty}`")
                             }
                             hir::BinOpKind::Rem => {
-                                format!("cannot mod `{lhs_ty}` by `{rhs_ty}`")
+                                format!(
+                                    "cannot calculate the remainder of `{lhs_ty}` divided by `{rhs_ty}`"
+                                )
                             }
                             hir::BinOpKind::BitAnd => {
                                 format!("no implementation for `{lhs_ty} & {rhs_ty}`")
@@ -488,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 46e7813d99e562cd1cff9b39b0224eaa75048fb1..7db4d92a177a1b89b13e9c93f58a3a6f9babe43d 100644 (file)
@@ -129,7 +129,7 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                 let a_types = infcx.tcx.anonymize_bound_vars(a_types);
                 let b_types = infcx.tcx.anonymize_bound_vars(b_types);
                 if a_types.bound_vars() == b_types.bound_vars() {
-                    let (a_types, b_types) = infcx.replace_bound_vars_with_placeholders(
+                    let (a_types, b_types) = infcx.instantiate_binder_with_placeholders(
                         a_types.map_bound(|a_types| (a_types, b_types.skip_binder())),
                     );
                     for (a, b) in std::iter::zip(a_types, b_types) {
index 554a70265d43ce04b4fd84d806b0583750cecb45..86f3174b7b2bb25e9c82d410761a445a4a5760f9 100644 (file)
@@ -60,7 +60,7 @@
 
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg};
-use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
+use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -1470,51 +1470,17 @@ fn add_labels_for_types(
                 for (key, values) in types.iter() {
                     let count = values.len();
                     let kind = key.descr();
-                    let mut returned_async_output_error = false;
                     for &sp in values {
-                        if sp.is_desugaring(DesugaringKind::Async) && !returned_async_output_error {
-                            if [sp] != err.span.primary_spans() {
-                                let mut span: MultiSpan = sp.into();
-                                span.push_span_label(
-                                    sp,
-                                    format!(
-                                        "checked the `Output` of this `async fn`, {}{} {}{}",
-                                        if count > 1 { "one of the " } else { "" },
-                                        target,
-                                        kind,
-                                        pluralize!(count),
-                                    ),
-                                );
-                                err.span_note(
-                                    span,
-                                    "while checking the return type of the `async fn`",
-                                );
-                            } else {
-                                err.span_label(
-                                    sp,
-                                    format!(
-                                        "checked the `Output` of this `async fn`, {}{} {}{}",
-                                        if count > 1 { "one of the " } else { "" },
-                                        target,
-                                        kind,
-                                        pluralize!(count),
-                                    ),
-                                );
-                                err.note("while checking the return type of the `async fn`");
-                            }
-                            returned_async_output_error = true;
-                        } else {
-                            err.span_label(
-                                sp,
-                                format!(
-                                    "{}{} {}{}",
-                                    if count == 1 { "the " } else { "one of the " },
-                                    target,
-                                    kind,
-                                    pluralize!(count),
-                                ),
-                            );
-                        }
+                        err.span_label(
+                            sp,
+                            format!(
+                                "{}{} {}{}",
+                                if count == 1 { "the " } else { "one of the " },
+                                target,
+                                kind,
+                                pluralize!(count),
+                            ),
+                        );
                     }
                 }
             }
@@ -1537,7 +1503,11 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                     //    |
                     //    = note: expected unit type `()`
                     //                 found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14 x:_]`
-                    if !self.ignore_span.overlaps(span) {
+                    //
+                    // Also ignore opaque `Future`s that come from async fns.
+                    if !self.ignore_span.overlaps(span)
+                        && !span.is_desugaring(DesugaringKind::Async)
+                    {
                         self.types.entry(kind).or_default().insert(span);
                     }
                 }
@@ -1952,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 31be107b35472a44dd373d95a7cc17df856b9a94..412e52d8fd7e21bbd2f9143ba587dbabcb7fa7ad 100644 (file)
@@ -38,13 +38,13 @@ pub fn higher_ranked_sub<T>(
         // First, we instantiate each bound region in the supertype with a
         // fresh placeholder region. Note that this automatically creates
         // a new universe if needed.
-        let sup_prime = self.infcx.replace_bound_vars_with_placeholders(sup);
+        let sup_prime = self.infcx.instantiate_binder_with_placeholders(sup);
 
         // Next, we instantiate each bound region in the subtype
         // with a fresh region variable. These region variables --
         // but no other pre-existing region variables -- can name
         // the placeholders.
-        let sub_prime = self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, sub);
+        let sub_prime = self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub);
 
         debug!("a_prime={:?}", sub_prime);
         debug!("b_prime={:?}", sup_prime);
@@ -70,7 +70,7 @@ impl<'tcx> InferCtxt<'tcx> {
     ///
     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
     #[instrument(level = "debug", skip(self), ret)]
-    pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
+    pub fn instantiate_binder_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
     where
         T: TypeFoldable<'tcx> + Copy,
     {
index f39170bb2916de0802b05016d86ef28b90429659..35918b8bae1c20b10290401962683d9a88ed13df 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;
@@ -995,7 +995,7 @@ pub fn subtype_predicate(
 
         Ok(self.commit_if_ok(|_snapshot| {
             let ty::SubtypePredicate { a_is_expected, a, b } =
-                self.replace_bound_vars_with_placeholders(predicate);
+                self.instantiate_binder_with_placeholders(predicate);
 
             let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
 
@@ -1008,7 +1008,7 @@ pub fn region_outlives_predicate(
         cause: &traits::ObligationCause<'tcx>,
         predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
     ) {
-        let ty::OutlivesPredicate(r_a, r_b) = self.replace_bound_vars_with_placeholders(predicate);
+        let ty::OutlivesPredicate(r_a, r_b) = self.instantiate_binder_with_placeholders(predicate);
         let origin =
             SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span));
         self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
@@ -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)
@@ -1447,7 +1447,14 @@ pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: T) -> FixupResult<'tcx
         value
     }
 
-    pub fn replace_bound_vars_with_fresh_vars<T>(
+    // Instantiates the bound variables in a given binder with fresh inference
+    // variables in the current universe.
+    //
+    // Use this method if you'd like to find some substitution of the binder's
+    // variables (e.g. during a method call). If there isn't a [`LateBoundRegionConversionTime`]
+    // that corresponds to your use case, consider whether or not you should
+    // use [`InferCtxt::instantiate_binder_with_placeholders`] instead.
+    pub fn instantiate_binder_with_fresh_vars<T>(
         &self,
         span: Span,
         lbrct: LateBoundRegionConversionTime,
@@ -1870,9 +1877,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 +1917,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 51c34f0d55f6ff715336cc2b45d53c3e2df19a16..532fbd0ffe4c40c685a47ef74098d5945fdacd60 100644 (file)
@@ -161,7 +161,7 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                 let a_types = infcx.tcx.anonymize_bound_vars(a_types);
                 let b_types = infcx.tcx.anonymize_bound_vars(b_types);
                 if a_types.bound_vars() == b_types.bound_vars() {
-                    let (a_types, b_types) = infcx.replace_bound_vars_with_placeholders(
+                    let (a_types, b_types) = infcx.instantiate_binder_with_placeholders(
                         a_types.map_bound(|a_types| (a_types, b_types.skip_binder())),
                     );
                     for (a, b) in std::iter::zip(a_types, b_types) {
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 4c9b3df2dbd33d706d04c3cc5e911ceeb9c70a2c..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,
                         },
                     );
                 }
@@ -495,6 +509,7 @@ enum UnusedDelimsCtx {
     ArrayLenExpr,
     AnonConst,
     MatchArmExpr,
+    IndexExpr,
 }
 
 impl From<UnusedDelimsCtx> for &'static str {
@@ -514,6 +529,7 @@ fn from(ctx: UnusedDelimsCtx) -> &'static str {
             UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression",
             UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
             UnusedDelimsCtx::MatchArmExpr => "match arm expression",
+            UnusedDelimsCtx::IndexExpr => "index expression",
         }
     }
 }
@@ -661,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)
@@ -733,6 +753,8 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
                 (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None)
             }
 
+            Index(_, ref value) => (value, UnusedDelimsCtx::IndexExpr, false, None, None),
+
             Assign(_, ref value, _) | AssignOp(.., ref value) => {
                 (value, UnusedDelimsCtx::AssignedValue, false, None, None)
             }
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 e405462bbb862268856c601acf1e0711bbce8cdd..12bcd939bd61b78e74b974b75eece249ca5d8680 100644 (file)
@@ -322,11 +322,7 @@ fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> Token
                 let generated_code = self
                     .generate_inner_field_code(
                         attr,
-                        FieldInfo {
-                            binding: binding_info,
-                            ty: inner_ty.inner_type().unwrap_or(&field.ty),
-                            span: &field.span(),
-                        },
+                        FieldInfo { binding: binding_info, ty: inner_ty, span: &field.span() },
                         binding,
                     )
                     .unwrap_or_else(|v| v.to_compile_error());
@@ -418,9 +414,9 @@ fn generate_inner_field_code(
                 Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
             }
             SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
-                if type_matches_path(info.ty, &["rustc_span", "Span"]) {
+                if type_matches_path(info.ty.inner_type(), &["rustc_span", "Span"]) {
                     Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
-                } else if type_is_unit(info.ty) {
+                } else if type_is_unit(info.ty.inner_type()) {
                     Ok(self.add_subdiagnostic(&fn_ident, slug))
                 } else {
                     report_type_error(attr, "`Span` or `()`")?
@@ -432,6 +428,15 @@ fn generate_inner_field_code(
                 code_field,
                 code_init,
             } => {
+                if let FieldInnerTy::Vec(_) = info.ty {
+                    throw_invalid_attr!(attr, &meta, |diag| {
+                        diag
+                        .note("`#[suggestion(...)]` applied to `Vec` field is ambiguous")
+                        .help("to show a suggestion consisting of multiple parts, use a `Subdiagnostic` annotated with `#[multipart_suggestion(...)]`")
+                        .help("to show a variable set of suggestions, use a `Vec` of `Subdiagnostic`s annotated with `#[suggestion(...)]`")
+                    });
+                }
+
                 let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
 
                 if let Some((static_applicability, span)) = static_applicability {
@@ -489,7 +494,7 @@ fn span_and_applicability_of_ty(
         &self,
         info: FieldInfo<'_>,
     ) -> Result<(TokenStream, SpannedOption<TokenStream>), DiagnosticDeriveError> {
-        match &info.ty {
+        match &info.ty.inner_type() {
             // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
             ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
                 let binding = &info.binding.binding;
index baffd3cec9c55394dfea79608bb7c3fe840e04c9..906e4c0b0e16c293faa07d0e4558d482a1627579 100644 (file)
@@ -247,11 +247,7 @@ fn generate_field_attr_code(
                     return quote! {};
                 }
 
-                let info = FieldInfo {
-                    binding,
-                    ty: inner_ty.inner_type().unwrap_or(&ast.ty),
-                    span: &ast.span(),
-                };
+                let info = FieldInfo { binding, ty: inner_ty, span: &ast.span() };
 
                 let generated = self
                     .generate_field_code_inner(kind_stats, attr, info, inner_ty.will_iterate())
@@ -312,6 +308,21 @@ fn generate_field_code_inner_path(
                     let binding = info.binding.binding.clone();
                     // FIXME(#100717): support `Option<Span>` on `primary_span` like in the
                     // diagnostic derive
+                    if !matches!(info.ty, FieldInnerTy::Plain(_)) {
+                        throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
+                            let diag = diag.note("there must be exactly one primary span");
+
+                            if kind_stats.has_normal_suggestion {
+                                diag.help(
+                                    "to create a suggestion with multiple spans, \
+                                     use `#[multipart_suggestion]` instead",
+                                )
+                            } else {
+                                diag
+                            }
+                        });
+                    }
+
                     self.span_field.set_once(binding, span);
                 }
 
index 6f52a3de1b151ad26c833937addc22fd38753038..27b8f676f3fbb8cec626e05a44e97b1ade90da4c 100644 (file)
@@ -80,7 +80,7 @@ fn report_error_if_not_applied_to_ty(
     path: &[&str],
     ty_name: &str,
 ) -> Result<(), DiagnosticDeriveError> {
-    if !type_matches_path(info.ty, path) {
+    if !type_matches_path(info.ty.inner_type(), path) {
         report_type_error(attr, ty_name)?;
     }
 
@@ -105,8 +105,8 @@ pub(crate) fn report_error_if_not_applied_to_span(
     attr: &Attribute,
     info: &FieldInfo<'_>,
 ) -> Result<(), DiagnosticDeriveError> {
-    if !type_matches_path(info.ty, &["rustc_span", "Span"])
-        && !type_matches_path(info.ty, &["rustc_errors", "MultiSpan"])
+    if !type_matches_path(info.ty.inner_type(), &["rustc_span", "Span"])
+        && !type_matches_path(info.ty.inner_type(), &["rustc_errors", "MultiSpan"])
     {
         report_type_error(attr, "`Span` or `MultiSpan`")?;
     }
@@ -115,44 +115,50 @@ pub(crate) fn report_error_if_not_applied_to_span(
 }
 
 /// Inner type of a field and type of wrapper.
+#[derive(Copy, Clone)]
 pub(crate) enum FieldInnerTy<'ty> {
     /// Field is wrapped in a `Option<$inner>`.
     Option(&'ty Type),
     /// Field is wrapped in a `Vec<$inner>`.
     Vec(&'ty Type),
     /// Field isn't wrapped in an outer type.
-    None,
+    Plain(&'ty Type),
 }
 
 impl<'ty> FieldInnerTy<'ty> {
     /// Returns inner type for a field, if there is one.
     ///
-    /// - If `ty` is an `Option`, returns `FieldInnerTy::Option { inner: (inner type) }`.
-    /// - If `ty` is a `Vec`, returns `FieldInnerTy::Vec { inner: (inner type) }`.
-    /// - Otherwise returns `None`.
+    /// - If `ty` is an `Option<Inner>`, returns `FieldInnerTy::Option(Inner)`.
+    /// - If `ty` is a `Vec<Inner>`, returns `FieldInnerTy::Vec(Inner)`.
+    /// - Otherwise returns `FieldInnerTy::Plain(ty)`.
     pub(crate) fn from_type(ty: &'ty Type) -> Self {
-        let variant: &dyn Fn(&'ty Type) -> FieldInnerTy<'ty> =
-            if type_matches_path(ty, &["std", "option", "Option"]) {
-                &FieldInnerTy::Option
-            } else if type_matches_path(ty, &["std", "vec", "Vec"]) {
-                &FieldInnerTy::Vec
-            } else {
-                return FieldInnerTy::None;
+        fn single_generic_type(ty: &Type) -> &Type {
+            let Type::Path(ty_path) = ty else {
+                panic!("expected path type");
             };
 
-        if let Type::Path(ty_path) = ty {
             let path = &ty_path.path;
             let ty = path.segments.iter().last().unwrap();
-            if let syn::PathArguments::AngleBracketed(bracketed) = &ty.arguments {
-                if bracketed.args.len() == 1 {
-                    if let syn::GenericArgument::Type(ty) = &bracketed.args[0] {
-                        return variant(ty);
-                    }
-                }
-            }
+            let syn::PathArguments::AngleBracketed(bracketed) = &ty.arguments else {
+                panic!("expected bracketed generic arguments");
+            };
+
+            assert_eq!(bracketed.args.len(), 1);
+
+            let syn::GenericArgument::Type(ty) = &bracketed.args[0] else {
+                panic!("expected generic parameter to be a type generic");
+            };
+
+            ty
         }
 
-        unreachable!();
+        if type_matches_path(ty, &["std", "option", "Option"]) {
+            FieldInnerTy::Option(single_generic_type(ty))
+        } else if type_matches_path(ty, &["std", "vec", "Vec"]) {
+            FieldInnerTy::Vec(single_generic_type(ty))
+        } else {
+            FieldInnerTy::Plain(ty)
+        }
     }
 
     /// Returns `true` if `FieldInnerTy::with` will result in iteration for this inner type (i.e.
@@ -160,15 +166,16 @@ pub(crate) fn from_type(ty: &'ty Type) -> Self {
     pub(crate) fn will_iterate(&self) -> bool {
         match self {
             FieldInnerTy::Vec(..) => true,
-            FieldInnerTy::Option(..) | FieldInnerTy::None => false,
+            FieldInnerTy::Option(..) | FieldInnerTy::Plain(_) => false,
         }
     }
 
-    /// Returns `Option` containing inner type if there is one.
-    pub(crate) fn inner_type(&self) -> Option<&'ty Type> {
+    /// Returns the inner type.
+    pub(crate) fn inner_type(&self) -> &'ty Type {
         match self {
-            FieldInnerTy::Option(inner) | FieldInnerTy::Vec(inner) => Some(inner),
-            FieldInnerTy::None => None,
+            FieldInnerTy::Option(inner) | FieldInnerTy::Vec(inner) | FieldInnerTy::Plain(inner) => {
+                inner
+            }
         }
     }
 
@@ -185,7 +192,7 @@ pub(crate) fn with(&self, binding: impl ToTokens, inner: impl ToTokens) -> Token
                     #inner
                 }
             },
-            FieldInnerTy::None => quote! { #inner },
+            FieldInnerTy::Plain(..) => quote! { #inner },
         }
     }
 }
@@ -194,7 +201,7 @@ pub(crate) fn with(&self, binding: impl ToTokens, inner: impl ToTokens) -> Token
 /// `generate_*` methods from walking the attributes themselves.
 pub(crate) struct FieldInfo<'a> {
     pub(crate) binding: &'a BindingInfo<'a>,
-    pub(crate) ty: &'a Type,
+    pub(crate) ty: FieldInnerTy<'a>,
     pub(crate) span: &'a proc_macro2::Span,
 }
 
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 5bd6b0704426b667b4e0435cd4ac3bb30f5f66a8..7f2994fd79b98af288b56103a3482b240ebc5bc7 100644 (file)
@@ -290,7 +290,7 @@ pub fn opt_parent_id(self, id: HirId) -> Option<HirId> {
     #[track_caller]
     pub fn parent_id(self, hir_id: HirId) -> HirId {
         self.opt_parent_id(hir_id)
-            .unwrap_or_else(|| bug!("No parent for node {:?}", self.node_to_string(hir_id)))
+            .unwrap_or_else(|| bug!("No parent for node {}", self.node_to_string(hir_id)))
     }
 
     pub fn get_parent(self, hir_id: HirId) -> Node<'hir> {
@@ -1191,12 +1191,10 @@ fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> {
 }
 
 fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
-    let id_str = format!(" (hir_id={})", id);
-
     let path_str = |def_id: LocalDefId| map.tcx.def_path_str(def_id.to_def_id());
 
     let span_str = || map.tcx.sess.source_map().span_to_snippet(map.span(id)).unwrap_or_default();
-    let node_str = |prefix| format!("{} {}{}", prefix, span_str(), id_str);
+    let node_str = |prefix| format!("{id} ({prefix} `{}`)", span_str());
 
     match map.find(id) {
         Some(Node::Item(item)) => {
@@ -1225,10 +1223,10 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
                 ItemKind::TraitAlias(..) => "trait alias",
                 ItemKind::Impl { .. } => "impl",
             };
-            format!("{} {}{}", item_str, path_str(item.owner_id.def_id), id_str)
+            format!("{id} ({item_str} {})", path_str(item.owner_id.def_id))
         }
         Some(Node::ForeignItem(item)) => {
-            format!("foreign item {}{}", path_str(item.owner_id.def_id), id_str)
+            format!("{id} (foreign item {})", path_str(item.owner_id.def_id))
         }
         Some(Node::ImplItem(ii)) => {
             let kind = match ii.kind {
@@ -1236,7 +1234,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
                 ImplItemKind::Fn(..) => "method",
                 ImplItemKind::Type(_) => "assoc type",
             };
-            format!("{} {} in {}{}", kind, ii.ident, path_str(ii.owner_id.def_id), id_str)
+            format!("{id} ({kind} `{}` in {})", ii.ident, path_str(ii.owner_id.def_id))
         }
         Some(Node::TraitItem(ti)) => {
             let kind = match ti.kind {
@@ -1245,13 +1243,13 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
                 TraitItemKind::Type(..) => "assoc type",
             };
 
-            format!("{} {} in {}{}", kind, ti.ident, path_str(ti.owner_id.def_id), id_str)
+            format!("{id} ({kind} `{}` in {})", ti.ident, path_str(ti.owner_id.def_id))
         }
         Some(Node::Variant(ref variant)) => {
-            format!("variant {} in {}{}", variant.ident, path_str(variant.def_id), id_str)
+            format!("{id} (variant `{}` in {})", variant.ident, path_str(variant.def_id))
         }
         Some(Node::Field(ref field)) => {
-            format!("field {} in {}{}", field.ident, path_str(field.def_id), id_str)
+            format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id))
         }
         Some(Node::AnonConst(_)) => node_str("const"),
         Some(Node::Expr(_)) => node_str("expr"),
@@ -1269,16 +1267,15 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
         Some(Node::Infer(_)) => node_str("infer"),
         Some(Node::Local(_)) => node_str("local"),
         Some(Node::Ctor(ctor)) => format!(
-            "ctor {}{}",
+            "{id} (ctor {})",
             ctor.ctor_def_id().map_or("<missing path>".into(), |def_id| path_str(def_id)),
-            id_str
         ),
         Some(Node::Lifetime(_)) => node_str("lifetime"),
         Some(Node::GenericParam(ref param)) => {
-            format!("generic_param {}{}", path_str(param.def_id), id_str)
+            format!("{id} (generic_param {})", path_str(param.def_id))
         }
-        Some(Node::Crate(..)) => String::from("root_crate"),
-        None => format!("unknown node{}", id_str),
+        Some(Node::Crate(..)) => String::from("(root_crate)"),
+        None => format!("{id} (unknown node)"),
     }
 }
 
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..0a16ede64991de8d36cd4adf23c1ac435a783e07 100644 (file)
     /// This is because the `hir_crate` query gives you access to all other items.
     /// To avoid this fate, do not call `tcx.hir().krate()`; instead,
     /// prefer wrappers like `tcx.visit_all_items_in_krate()`.
-    query hir_crate(key: ()) -> Crate<'tcx> {
+    query hir_crate(key: ()) -> &'tcx Crate<'tcx> {
         arena_cache
         eval_always
         desc { "getting the crate HIR" }
     }
 
     /// All items in the crate.
-    query hir_crate_items(_: ()) -> rustc_middle::hir::ModuleItems {
+    query hir_crate_items(_: ()) -> &'tcx rustc_middle::hir::ModuleItems {
         arena_cache
         eval_always
         desc { "getting HIR crate items" }
@@ -71,7 +71,7 @@
     ///
     /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.
     /// Avoid calling this query directly.
-    query hir_module_items(key: LocalDefId) -> rustc_middle::hir::ModuleItems {
+    query hir_module_items(key: LocalDefId) -> &'tcx rustc_middle::hir::ModuleItems {
         arena_cache
         desc { |tcx| "getting HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
         cache_on_disk_if { true }
         separate_provide_extern
     }
 
-    query unsizing_params_for_adt(key: DefId) -> rustc_index::bit_set::BitSet<u32>
+    query unsizing_params_for_adt(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32>
     {
         arena_cache
         desc { |tcx|
 
     /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
     /// associated generics.
-    query generics_of(key: DefId) -> ty::Generics {
+    query generics_of(key: DefId) -> &'tcx ty::Generics {
         desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) }
         arena_cache
         cache_on_disk_if { key.is_local() }
     /// These are assembled from the following places:
     /// - `extern` blocks (depending on their `link` attributes)
     /// - the `libs` (`-l`) option
-    query native_libraries(_: CrateNum) -> Vec<NativeLib> {
+    query native_libraries(_: CrateNum) -> &'tcx Vec<NativeLib> {
         arena_cache
         desc { "looking up the native libraries of a linked crate" }
         separate_provide_extern
     }
 
-    query shallow_lint_levels_on(key: hir::OwnerId) -> rustc_middle::lint::ShallowLintLevelMap {
+    query shallow_lint_levels_on(key: hir::OwnerId) -> &'tcx rustc_middle::lint::ShallowLintLevelMap {
         eval_always // fetches `resolutions`
         arena_cache
         desc { |tcx| "looking up lint levels for `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
-    query lint_expectations(_: ()) -> Vec<(LintExpectationId, LintExpectation)> {
+    query lint_expectations(_: ()) -> &'tcx Vec<(LintExpectationId, LintExpectation)> {
         arena_cache
         desc { "computing `#[expect]`ed lints in this crate" }
     }
     }
 
     /// Set of param indexes for type params that are in the type's representation
-    query params_in_repr(key: DefId) -> rustc_index::bit_set::BitSet<u32> {
+    query params_in_repr(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32> {
         desc { "finding type parameters in the representation" }
         arena_cache
         no_hash
     }
 
     /// Create a THIR tree for debugging.
-    query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> String {
+    query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String {
         no_hash
         arena_cache
         desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) }
     }
 
     /// Create a list-like THIR representation for debugging.
-    query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> String {
+    query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String {
         no_hash
         arena_cache
         desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.did.to_def_id()) }
     /// Set of all the `DefId`s in this crate that have MIR associated with
     /// them. This includes all the body owners, but also things like struct
     /// constructors.
-    query mir_keys(_: ()) -> rustc_data_structures::fx::FxIndexSet<LocalDefId> {
+    query mir_keys(_: ()) -> &'tcx rustc_data_structures::fx::FxIndexSet<LocalDefId> {
         arena_cache
         desc { "getting a list of all mir_keys" }
     }
 
     query symbols_for_closure_captures(
         key: (LocalDefId, LocalDefId)
-    ) -> Vec<rustc_span::Symbol> {
+    ) -> &'tcx Vec<rustc_span::Symbol> {
         arena_cache
         desc {
             |tcx| "finding symbols for captures of closure `{}` in `{}`",
         }
     }
 
-    query mir_generator_witnesses(key: DefId) -> mir::GeneratorLayout<'tcx> {
+    query mir_generator_witnesses(key: DefId) -> &'tcx mir::GeneratorLayout<'tcx> {
         arena_cache
         desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
 
     /// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
     /// MIR pass (assuming the -Cinstrument-coverage option is enabled).
-    query coverageinfo(key: ty::InstanceDef<'tcx>) -> mir::CoverageInfo {
+    query coverageinfo(key: ty::InstanceDef<'tcx>) -> &'tcx mir::CoverageInfo {
         desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key.def_id()) }
         arena_cache
     }
 
     /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the
     /// function was optimized out before codegen, and before being added to the Coverage Map.
-    query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> {
+    query covered_code_regions(key: DefId) -> &'tcx Vec<&'tcx mir::coverage::CodeRegion> {
         desc {
             |tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`",
             tcx.def_path_str(key)
         desc { "erasing regions from `{}`", ty }
     }
 
-    query wasm_import_module_map(_: CrateNum) -> FxHashMap<DefId, String> {
+    query wasm_import_module_map(_: CrateNum) -> &'tcx FxHashMap<DefId, String> {
         arena_cache
         desc { "getting wasm import module map" }
     }
         desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir().ty_param_name(key.1) }
     }
 
-    query trait_def(key: DefId) -> ty::TraitDef {
+    query trait_def(key: DefId) -> &'tcx ty::TraitDef {
         desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) }
         arena_cache
         cache_on_disk_if { key.is_local() }
     }
 
     /// Gets a map with the variance of every item; use `item_variance` instead.
-    query crate_variances(_: ()) -> ty::CrateVariancesMap<'tcx> {
+    query crate_variances(_: ()) -> &'tcx ty::CrateVariancesMap<'tcx> {
         arena_cache
         desc { "computing the variances for items in this crate" }
     }
     }
 
     /// Maps from thee `DefId` of a type to its (inferred) outlives.
-    query inferred_outlives_crate(_: ()) -> ty::CratePredicatesMap<'tcx> {
+    query inferred_outlives_crate(_: ()) -> &'tcx ty::CratePredicatesMap<'tcx> {
         arena_cache
         desc { "computing the inferred outlives predicates for items in this crate" }
     }
     }
 
     /// Maps from a trait item to the trait item "descriptor".
-    query associated_item(key: DefId) -> ty::AssocItem {
+    query associated_item(key: DefId) -> &'tcx ty::AssocItem {
         desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) }
         arena_cache
         cache_on_disk_if { key.is_local() }
     }
 
     /// Collects the associated items defined on a trait or impl.
-    query associated_items(key: DefId) -> ty::AssocItems<'tcx> {
+    query associated_items(key: DefId) -> &'tcx ty::AssocItems<'tcx> {
         arena_cache
         desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
     }
     ///
     /// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be
     ///`{ trait_f: impl_f, trait_g: impl_g }`
-    query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> {
+    query impl_item_implementor_ids(impl_id: DefId) -> &'tcx FxHashMap<DefId, DefId> {
         arena_cache
         desc { |tcx| "comparing impl items against trait for `{}`", tcx.def_path_str(impl_id) }
     }
     ///
     /// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone) and
     /// their respective impl (i.e., part of the derive macro)
-    query live_symbols_and_ignored_derived_traits(_: ()) -> (
+    query live_symbols_and_ignored_derived_traits(_: ()) -> &'tcx (
         FxHashSet<LocalDefId>,
         FxHashMap<LocalDefId, Vec<(DefId, DefId)>>
     ) {
 
     /// Gets a complete map from all types to their inherent impls.
     /// Not meant to be used directly outside of coherence.
-    query crate_inherent_impls(k: ()) -> CrateInherentImpls {
+    query crate_inherent_impls(k: ()) -> &'tcx CrateInherentImpls {
         arena_cache
         desc { "finding all inherent impls defined in crate" }
     }
         desc { "checking for private elements in public interfaces" }
     }
 
-    query reachable_set(_: ()) -> FxHashSet<LocalDefId> {
+    query reachable_set(_: ()) -> &'tcx FxHashSet<LocalDefId> {
         arena_cache
         desc { "reachability" }
     }
     }
 
     /// Generates a MIR body for the shim.
-    query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
+    query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::Body<'tcx> {
         arena_cache
         desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
     }
         separate_provide_extern
     }
 
-    query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs {
+    query codegen_fn_attrs(def_id: DefId) -> &'tcx CodegenFnAttrs {
         desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) }
         arena_cache
         cache_on_disk_if { def_id.is_local() }
     }
     /// Gets the rendered value of the specified constant or associated constant.
     /// Used by rustdoc.
-    query rendered_const(def_id: DefId) -> String {
+    query rendered_const(def_id: DefId) -> &'tcx String {
         arena_cache
         desc { |tcx| "rendering constant initializer of `{}`", tcx.def_path_str(def_id) }
         cache_on_disk_if { def_id.is_local() }
     }
 
     /// Given a trait `trait_id`, return all known `impl` blocks.
-    query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls {
+    query trait_impls_of(trait_id: DefId) -> &'tcx ty::trait_def::TraitImpls {
         arena_cache
         desc { |tcx| "finding trait impls of `{}`", tcx.def_path_str(trait_id) }
     }
 
-    query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph {
+    query specialization_graph_of(trait_id: DefId) -> &'tcx specialization_graph::Graph {
         arena_cache
         desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
         cache_on_disk_if { true }
         separate_provide_extern
     }
 
-    query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> {
+    query dependency_formats(_: ()) -> &'tcx Lrc<crate::middle::dependency_format::Dependencies> {
         arena_cache
         desc { "getting the linkage format of all dependencies" }
     }
     // Does not include external symbols that don't have a corresponding DefId,
     // like the compiler-generated `main` function and so on.
     query reachable_non_generics(_: CrateNum)
-        -> DefIdMap<SymbolExportInfo> {
+        -> &'tcx DefIdMap<SymbolExportInfo> {
         arena_cache
         desc { "looking up the exported symbols of a crate" }
         separate_provide_extern
     /// added or removed in any upstream crate. Instead use the narrower
     /// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even
     /// better, `Instance::upstream_monomorphization()`.
-    query upstream_monomorphizations(_: ()) -> DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> {
+    query upstream_monomorphizations(_: ()) -> &'tcx DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> {
         arena_cache
         desc { "collecting available upstream monomorphizations" }
     }
     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),
     }
 
     /// Returns a list of all `extern` blocks of a crate.
-    query foreign_modules(_: CrateNum) -> FxHashMap<DefId, ForeignModule> {
+    query foreign_modules(_: CrateNum) -> &'tcx FxHashMap<DefId, ForeignModule> {
         arena_cache
         desc { "looking up the foreign modules of a linked crate" }
         separate_provide_extern
 
     /// Gets the extra data to put in each output filename for a crate.
     /// For example, compiling the `foo` crate with `extra-filename=-a` creates a `libfoo-b.rlib` file.
-    query extra_filename(_: CrateNum) -> String {
+    query extra_filename(_: CrateNum) -> &'tcx String {
         arena_cache
         eval_always
         desc { "looking up the extra filename for a crate" }
     }
 
     /// Gets the paths where the crate came from in the file system.
-    query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> {
+    query crate_extern_paths(_: CrateNum) -> &'tcx Vec<PathBuf> {
         arena_cache
         eval_always
         desc { "looking up the paths for extern crates" }
     /// Does lifetime resolution on items. Importantly, we can't resolve
     /// lifetimes directly on things like trait methods, because of trait params.
     /// See `rustc_resolve::late::lifetimes for details.
-    query resolve_lifetimes(_: hir::OwnerId) -> ResolveLifetimes {
+    query resolve_lifetimes(_: hir::OwnerId) -> &'tcx ResolveLifetimes {
         arena_cache
         desc { "resolving lifetimes" }
     }
         desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
     }
 
-    query lib_features(_: ()) -> LibFeatures {
+    query lib_features(_: ()) -> &'tcx LibFeatures {
         arena_cache
         desc { "calculating the lib features map" }
     }
         desc { "calculating the lib features defined in a crate" }
         separate_provide_extern
     }
-    query stability_implications(_: CrateNum) -> FxHashMap<Symbol, Symbol> {
+    query stability_implications(_: CrateNum) -> &'tcx FxHashMap<Symbol, Symbol> {
         arena_cache
         desc { "calculating the implications between `#[unstable]` features defined in a crate" }
         separate_provide_extern
         separate_provide_extern
     }
     /// Returns the lang items defined in another crate by loading it from metadata.
-    query get_lang_items(_: ()) -> LanguageItems {
+    query get_lang_items(_: ()) -> &'tcx LanguageItems {
         arena_cache
         eval_always
         desc { "calculating the lang items map" }
     }
 
     /// Returns all diagnostic items defined in all crates.
-    query all_diagnostic_items(_: ()) -> rustc_hir::diagnostic_items::DiagnosticItems {
+    query all_diagnostic_items(_: ()) -> &'tcx rustc_hir::diagnostic_items::DiagnosticItems {
         arena_cache
         eval_always
         desc { "calculating the diagnostic items map" }
     }
 
     /// Returns the diagnostic items defined in a crate.
-    query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems {
+    query diagnostic_items(_: CrateNum) -> &'tcx rustc_hir::diagnostic_items::DiagnosticItems {
         arena_cache
         desc { "calculating the diagnostic items map in a crate" }
         separate_provide_extern
         desc { "calculating the missing lang items in a crate" }
         separate_provide_extern
     }
-    query visible_parent_map(_: ()) -> DefIdMap<DefId> {
+    query visible_parent_map(_: ()) -> &'tcx DefIdMap<DefId> {
         arena_cache
         desc { "calculating the visible parent map" }
     }
-    query trimmed_def_paths(_: ()) -> FxHashMap<DefId, Symbol> {
+    query trimmed_def_paths(_: ()) -> &'tcx FxHashMap<DefId, Symbol> {
         arena_cache
         desc { "calculating trimmed def paths" }
     }
         desc { "seeing if we're missing an `extern crate` item for this crate" }
         separate_provide_extern
     }
-    query used_crate_source(_: CrateNum) -> Lrc<CrateSource> {
+    query used_crate_source(_: CrateNum) -> &'tcx Lrc<CrateSource> {
         arena_cache
         eval_always
         desc { "looking at the source for a crate" }
         separate_provide_extern
     }
     /// Returns the debugger visualizers defined for this crate.
-    query debugger_visualizers(_: CrateNum) -> Vec<rustc_span::DebuggerVisualizerFile> {
+    query debugger_visualizers(_: CrateNum) -> &'tcx Vec<rustc_span::DebuggerVisualizerFile> {
         arena_cache
         desc { "looking up the debugger visualizers for this crate" }
         separate_provide_extern
         desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
     }
 
-    query stability_index(_: ()) -> stability::Index {
+    query stability_index(_: ()) -> &'tcx stability::Index {
         arena_cache
         eval_always
         desc { "calculating the stability index for the local crate" }
     ///
     /// This query returns an `&Arc` because codegen backends need the value even after the `TyCtxt`
     /// has been destroyed.
-    query output_filenames(_: ()) -> Arc<OutputFilenames> {
+    query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
         feedable
         desc { "getting output filenames" }
         arena_cache
         remap_env_constness
     }
 
-    query supported_target_features(_: CrateNum) -> FxHashMap<String, Option<Symbol>> {
+    query supported_target_features(_: CrateNum) -> &'tcx FxHashMap<String, Option<Symbol>> {
         arena_cache
         eval_always
         desc { "looking up supported target features" }
     /// span) for an *existing* error. Therefore, it is best-effort, and may never handle
     /// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine,
     /// because the `ty::Ty`-based wfcheck is always run.
-    query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, traits::WellFormedLoc)) -> Option<traits::ObligationCause<'tcx>> {
+    query diagnostic_hir_wf_check(
+        key: (ty::Predicate<'tcx>, traits::WellFormedLoc)
+    ) -> &'tcx Option<traits::ObligationCause<'tcx>> {
         arena_cache
         eval_always
         no_hash
         desc { "performing HIR wf-checking for predicate `{:?}` at item `{:?}`", key.0, key.1 }
     }
 
-
     /// The list of backend features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
     /// `--target` and similar).
-    query global_backend_features(_: ()) -> Vec<String> {
+    query global_backend_features(_: ()) -> &'tcx Vec<String> {
         arena_cache
         eval_always
         desc { "computing the backend features for CLI flags" }
     }
 
-    query generator_diagnostic_data(key: DefId) -> Option<GeneratorDiagnosticData<'tcx>> {
+    query generator_diagnostic_data(key: DefId) -> &'tcx Option<GeneratorDiagnosticData<'tcx>> {
         arena_cache
         desc { |tcx| "looking up generator diagnostic data of `{}`", tcx.def_path_str(key) }
         separate_provide_extern
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 b63b9e754cf466a963adc68740971e5f6fa0e0ff..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 {
@@ -2171,7 +2175,7 @@ pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
             self.late_bound_vars_map(id.owner)
                 .and_then(|map| map.get(&id.local_id).cloned())
                 .unwrap_or_else(|| {
-                    bug!("No bound vars found for {:?} ({:?})", self.hir().node_to_string(id), id)
+                    bug!("No bound vars found for {}", self.hir().node_to_string(id))
                 })
                 .iter(),
         )
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 e8e00d5feb873110e3df1a5d49d59c34e8bd79f9..bbb4fd999bc76d38aac4c76668dc8c29cc8da9fa 100644 (file)
@@ -675,8 +675,12 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                 p!(")")
             }
             ty::FnDef(def_id, substs) => {
-                let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs);
-                p!(print(sig), " {{", print_value_path(def_id, substs), "}}");
+                if NO_QUERIES.with(|q| q.get()) {
+                    p!(print_def_path(def_id, substs));
+                } else {
+                    let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs);
+                    p!(print(sig), " {{", print_value_path(def_id, substs), "}}");
+                }
             }
             ty::FnPtr(ref bare_fn) => p!(print(bare_fn)),
             ty::Infer(infer_ty) => {
@@ -734,13 +738,13 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
             }
             ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
-                // FIXME(eddyb) print this with `print_def_path`.
                 // We use verbose printing in 'NO_QUERIES' mode, to
                 // avoid needing to call `predicates_of`. This should
                 // only affect certain debug messages (e.g. messages printed
                 // from `rustc_middle::ty` during the computation of `tcx.predicates_of`),
                 // and should have no effect on any compiler output.
-                if self.should_print_verbose() || NO_QUERIES.with(|q| q.get()) {
+                if self.should_print_verbose() {
+                    // FIXME(eddyb) print this with `print_def_path`.
                     p!(write("Opaque({:?}, {:?})", def_id, substs));
                     return Ok(self);
                 }
@@ -748,6 +752,8 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                 let parent = self.tcx().parent(def_id);
                 match self.tcx().def_kind(parent) {
                     DefKind::TyAlias | DefKind::AssocTy => {
+                        // NOTE: I know we should check for NO_QUERIES here, but it's alright.
+                        // `type_of` on a type alias or assoc type should never cause a cycle.
                         if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, .. }) =
                             *self.tcx().type_of(parent).kind()
                         {
@@ -762,7 +768,14 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                         p!(print_def_path(def_id, substs));
                         return Ok(self);
                     }
-                    _ => return self.pretty_print_opaque_impl_type(def_id, substs),
+                    _ => {
+                        if NO_QUERIES.with(|q| q.get()) {
+                            p!(print_def_path(def_id, &[]));
+                            return Ok(self);
+                        } else {
+                            return self.pretty_print_opaque_impl_type(def_id, substs);
+                        }
+                    }
                 }
             }
             ty::Str => p!("str"),
index 1be819ca610c7c644f7b3c9c9325f4c52bf81494..933aaadd62e1dd4a34dfc36410a192d904b2f259 100644 (file)
@@ -106,31 +106,21 @@ 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> };
     ($K:ty) => { $K };
 }
 
-macro_rules! query_storage {
-    ([][$K:ty, $V:ty]) => {
-        <<$K as Key>::CacheSelector as CacheSelector<'tcx, $V>>::Cache
+macro_rules! query_if_arena {
+    ([] $arena:ty, $no_arena:ty) => {
+        $no_arena
     };
-    ([(arena_cache) $($rest:tt)*][$K:ty, $V:ty]) => {
-        <<$K as Key>::CacheSelector as CacheSelector<'tcx, $V>>::ArenaCache
+    ([(arena_cache) $($rest:tt)*] $arena:ty, $no_arena:ty) => {
+        $arena
     };
-    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
-        query_storage!([$($modifiers)*][$($args)*])
+    ([$other:tt $($modifiers:tt)*]$($args:tt)*) => {
+        query_if_arena!([$($modifiers)*]$($args)*)
     };
 }
 
@@ -194,23 +184,30 @@ pub mod query_keys {
 
             $(pub type $name<'tcx> = $($K)*;)*
         }
-        #[allow(nonstandard_style, unused_lifetimes)]
+        #[allow(nonstandard_style, unused_lifetimes, unused_parens)]
         pub mod query_values {
             use super::*;
 
-            $(pub type $name<'tcx> = $V;)*
+            $(pub type $name<'tcx> = query_if_arena!([$($modifiers)*] <$V as Deref>::Target, $V);)*
         }
-        #[allow(nonstandard_style, unused_lifetimes)]
+        #[allow(nonstandard_style, unused_lifetimes, unused_parens)]
         pub mod query_storage {
             use super::*;
 
-            $(pub type $name<'tcx> = query_storage!([$($modifiers)*][$($K)*, $V]);)*
+            $(
+                pub type $name<'tcx> = query_if_arena!([$($modifiers)*]
+                    <<$($K)* as Key>::CacheSelector
+                        as CacheSelector<'tcx, <$V as Deref>::Target>>::ArenaCache,
+                    <<$($K)* as Key>::CacheSelector as CacheSelector<'tcx, $V>>::Cache
+                );
+            )*
         }
+
         #[allow(nonstandard_style, unused_lifetimes)]
         pub mod query_stored {
             use super::*;
 
-            $(pub type $name<'tcx> = <query_storage::$name<'tcx> as QueryStorage>::Stored;)*
+            $(pub type $name<'tcx> = $V;)*
         }
 
         #[derive(Default)]
@@ -225,14 +222,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),
+                };
             })*
         }
 
@@ -240,7 +233,7 @@ impl<'tcx> TyCtxt<'tcx> {
             $($(#[$attr])*
             #[inline(always)]
             #[must_use]
-            pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx>
+            pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V
             {
                 self.at(DUMMY_SP).$name(key)
             })*
@@ -249,19 +242,15 @@ pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'
         impl<'tcx> TyCtxtAt<'tcx> {
             $($(#[$attr])*
             #[inline(always)]
-            pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx>
+            pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V
             {
                 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()
             })*
         }
 
@@ -324,7 +313,7 @@ fn $name(
                 span: Span,
                 key: query_keys::$name<'tcx>,
                 mode: QueryMode,
-            ) -> Option<query_stored::$name<'tcx>>;)*
+            ) -> Option<$V>;)*
         }
     };
 }
@@ -346,34 +335,32 @@ macro_rules! define_feedable {
         $(impl<'tcx, K: IntoQueryParam<$($K)*> + Copy> TyCtxtFeed<'tcx, K> {
             $(#[$attr])*
             #[inline(always)]
-            pub fn $name(self, value: $V) -> query_stored::$name<'tcx> {
+            pub fn $name(self, value: query_values::$name<'tcx>) -> $V {
                 let key = self.key().into_query_param();
                 opt_remap_env_constness!([$($modifiers)*][key]);
 
                 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 060d864389cb0f4ffa3f3c84b9f9ab5bcb353705..98d6b68356368c14e06717b05a5c4ccc72e05915 100644 (file)
@@ -2043,6 +2043,28 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         cf.is_break()
     }
 
+    /// Checks whether a type recursively contains any closure
+    ///
+    /// Example: `Option<[closure@file.rs:4:20]>` returns true
+    pub fn contains_closure(self) -> bool {
+        struct ContainsClosureVisitor;
+
+        impl<'tcx> TypeVisitor<'tcx> for ContainsClosureVisitor {
+            type BreakTy = ();
+
+            fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+                if let ty::Closure(_, _) = t.kind() {
+                    ControlFlow::Break(())
+                } else {
+                    t.super_visit_with(self)
+                }
+            }
+        }
+
+        let cf = self.visit_with(&mut ContainsClosureVisitor);
+        cf.is_break()
+    }
+
     /// Returns the type and mutability of `*ty`.
     ///
     /// The parameter `explicit` indicates if this is an *explicit* dereference.
index 79a6c730d7159a5abcbf323ae029566c709952e6..9beaac87183a7fcde3369cab7949c5eca5a299ee 100644 (file)
@@ -372,7 +372,7 @@ pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
 
     pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
         self.node_type_opt(id).unwrap_or_else(|| {
-            bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id)))
+            bug!("node_type: no type for node {}", tls::with(|tcx| tcx.hir().node_to_string(id)))
         })
     }
 
@@ -551,9 +551,8 @@ fn validate_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
 fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
     ty::tls::with(|tcx| {
         bug!(
-            "node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}",
+            "node {} cannot be placed in TypeckResults with hir_owner {:?}",
             tcx.hir().node_to_string(hir_id),
-            hir_id.owner,
             hir_owner
         )
     });
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 3224e13f7af4bfe9da8c9fd3b045edadee2b5496..0d466bbe56e01d82b7d5550ca8dc2688495c3a0c 100644 (file)
@@ -1,5 +1,5 @@
 use crate::elaborate_drops::DropFlagState;
-use rustc_middle::mir::{self, Body, Location};
+use rustc_middle::mir::{self, Body, Location, Terminator, TerminatorKind};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_target::abi::VariantIdx;
 
@@ -194,6 +194,17 @@ pub fn drop_flag_effects_for_location<'tcx, F>(
         on_all_children_bits(tcx, body, move_data, path, |mpi| callback(mpi, DropFlagState::Absent))
     }
 
+    // Drop does not count as a move but we should still consider the variable uninitialized.
+    if let Some(Terminator { kind: TerminatorKind::Drop { place, .. }, .. }) =
+        body.stmt_at(loc).right()
+    {
+        if let LookupResult::Exact(mpi) = move_data.rev_lookup.find(place.as_ref()) {
+            on_all_children_bits(tcx, body, move_data, mpi, |mpi| {
+                callback(mpi, DropFlagState::Absent)
+            })
+        }
+    }
+
     debug!("drop_flag_effects: assignment for location({:?})", loc);
 
     for_location_inits(tcx, body, move_data, loc, |mpi| callback(mpi, DropFlagState::Present));
index 0195693a7cb0e6d9bf8639e83d8e96a5b59797a3..115c8afcce0cf7c15964bd53b175366c0ac6b7fd 100644 (file)
@@ -376,7 +376,8 @@ fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
             | TerminatorKind::Resume
             | TerminatorKind::Abort
             | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Unreachable => {}
+            | TerminatorKind::Unreachable
+            | TerminatorKind::Drop { .. } => {}
 
             TerminatorKind::Assert { ref cond, .. } => {
                 self.gather_operand(cond);
@@ -391,10 +392,6 @@ fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
                 self.create_move_path(place);
                 self.gather_init(place.as_ref(), InitKind::Deep);
             }
-
-            TerminatorKind::Drop { place, target: _, unwind: _ } => {
-                self.gather_move(place);
-            }
             TerminatorKind::DropAndReplace { place, ref value, .. } => {
                 self.create_move_path(place);
                 self.gather_operand(value);
index 6bdbda909d7bdf02da963730db84fa2a3d2be991..a6ef2a742c8736219f84946e85a8e6e44ee2c544 100644 (file)
@@ -223,13 +223,13 @@ fn handle_terminator(&self, terminator: &Terminator<'tcx>, state: &mut State<Sel
         self.super_terminator(terminator, state)
     }
 
-    fn super_terminator(&self, terminator: &Terminator<'tcx>, _state: &mut State<Self::Value>) {
+    fn super_terminator(&self, terminator: &Terminator<'tcx>, state: &mut State<Self::Value>) {
         match &terminator.kind {
             TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => {
                 // Effect is applied by `handle_call_return`.
             }
-            TerminatorKind::Drop { .. } => {
-                // We don't track dropped places.
+            TerminatorKind::Drop { place, .. } => {
+                state.flood_with(place.as_ref(), self.map(), Self::Value::bottom());
             }
             TerminatorKind::DropAndReplace { .. } | TerminatorKind::Yield { .. } => {
                 // They would have an effect, but are not allowed in this phase.
@@ -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 182b3015dd7d784c4ad215d834d749e2915d73e6..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);
         }
@@ -162,17 +163,20 @@ fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
     }
 
     fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, loc: Location) {
-        if let StatementKind::StorageDead(l) = stmt.kind
-            && self.storage_to_remove.contains(l)
-        {
-            stmt.make_nop();
-        } else if let StatementKind::Assign(box (ref place, ref mut rvalue)) = stmt.kind
-            && place.as_local().is_some()
-        {
-            // Do not replace assignments.
-            self.visit_rvalue(rvalue, loc)
-        } else {
-            self.super_statement(stmt, loc);
+        match stmt.kind {
+            // When removing storage statements, we need to remove both (#107511).
+            StatementKind::StorageLive(l) | StatementKind::StorageDead(l)
+                if self.storage_to_remove.contains(l) =>
+            {
+                stmt.make_nop()
+            }
+            StatementKind::Assign(box (ref place, ref mut rvalue))
+                if place.as_local().is_some() =>
+            {
+                // Do not replace assignments.
+                self.visit_rvalue(rvalue, loc)
+            }
+            _ => self.super_statement(stmt, loc),
         }
     }
 }
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 65f4956d23acd5e7722e75caf517269a838b21d7..c2ff8645635e01597ea6c0d55ece679df9e80f9f 100644 (file)
 use rustc_target::abi::VariantIdx;
 use std::fmt;
 
+/// During MIR building, Drop and DropAndReplace terminators are inserted in every place where a drop may occur.
+/// However, in this phase, the presence of these terminators does not guarantee that a destructor will run,
+/// as the target of the drop may be uninitialized.
+/// In general, the compiler cannot determine at compile time whether a destructor will run or not.
+///
+/// At a high level, this pass refines Drop and DropAndReplace to only run the destructor if the
+/// target is initialized. The way this is achievied is by inserting drop flags for every variable
+/// that may be dropped, and then using those flags to determine whether a destructor should run.
+/// This pass also removes DropAndReplace, replacing it with a Drop paired with an assign statement.
+/// Once this is complete, Drop terminators in the MIR correspond to a call to the "drop glue" or
+/// "drop shim" for the type of the dropped place.
+///
+/// This pass relies on dropped places having an associated move path, which is then used to determine
+/// the initialization status of the place and its descendants.
+/// It's worth noting that a MIR containing a Drop without an associated move path is probably ill formed,
+/// as it would allow running a destructor on a place behind a reference:
+///
+/// ```text
+// fn drop_term<T>(t: &mut T) {
+//     mir!(
+//         {
+//             Drop(*t, exit)
+//         }
+//         exit = {
+//             Return()
+//         }
+//     )
+// }
+/// ```
 pub struct ElaborateDrops;
 
 impl<'tcx> MirPass<'tcx> for ElaborateDrops {
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 054b41b478d60516d53c729faa2f1ecdcd1bb5d9..0c11e0026900e4c2f5b5c6abb931ca3a460f8cc4 100644 (file)
@@ -1,8 +1,11 @@
+use std::borrow::Cow;
+
 use rustc_ast::token::Token;
-use rustc_ast::Path;
+use rustc_ast::{Path, Visibility};
 use rustc_errors::{fluent, AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_session::errors::ExprParenthesesNeeded;
+use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, Symbol};
 
@@ -351,7 +354,7 @@ pub(crate) enum IfExpressionMissingThenBlockSub {
 }
 
 #[derive(Subdiagnostic)]
-#[help(parse_extra_if_in_let_else)]
+#[suggestion(parse_extra_if_in_let_else, applicability = "maybe-incorrect", code = "")]
 pub(crate) struct IfExpressionLetSomeSub {
     #[primary_span]
     pub if_span: Span,
@@ -430,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 {
@@ -667,13 +682,10 @@ pub(crate) struct InclusiveRangeExtraEquals {
 #[diag(parse_inclusive_range_match_arrow)]
 pub(crate) struct InclusiveRangeMatchArrow {
     #[primary_span]
+    pub arrow: Span,
+    #[label]
     pub span: Span,
-    #[suggestion(
-        suggestion_add_space,
-        style = "verbose",
-        code = " ",
-        applicability = "machine-applicable"
-    )]
+    #[suggestion(style = "verbose", code = " ", applicability = "machine-applicable")]
     pub after_pat: Span,
 }
 
@@ -1330,3 +1342,617 @@ pub(crate) struct WhereClauseBeforeTupleStructBodySugg {
     #[suggestion_part(code = "")]
     pub right: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(parse_async_fn_in_2015, code = "E0670")]
+pub(crate) struct AsyncFnIn2015 {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[subdiagnostic]
+    pub help: HelpUseLatestEdition,
+}
+
+#[derive(Subdiagnostic)]
+#[label(parse_async_block_in_2015)]
+pub(crate) struct AsyncBlockIn2015 {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_self_argument_pointer)]
+pub(crate) struct SelfArgumentPointer {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_visibility_not_followed_by_item)]
+#[help]
+pub(crate) struct VisibilityNotFollowedByItem {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub vis: Visibility,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_default_not_followed_by_item)]
+#[note]
+pub(crate) struct DefaultNotFollowedByItem {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+pub(crate) enum MissingKeywordForItemDefinition {
+    #[diag(parse_missing_struct_for_struct_definition)]
+    Struct {
+        #[primary_span]
+        #[suggestion(style = "short", applicability = "maybe-incorrect", code = " struct ")]
+        span: Span,
+        ident: Ident,
+    },
+    #[diag(parse_missing_fn_for_function_definition)]
+    Function {
+        #[primary_span]
+        #[suggestion(style = "short", applicability = "maybe-incorrect", code = " fn ")]
+        span: Span,
+        ident: Ident,
+    },
+    #[diag(parse_missing_fn_for_method_definition)]
+    Method {
+        #[primary_span]
+        #[suggestion(style = "short", applicability = "maybe-incorrect", code = " fn ")]
+        span: Span,
+        ident: Ident,
+    },
+    #[diag(parse_ambiguous_missing_keyword_for_item_definition)]
+    Ambiguous {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiag: Option<AmbiguousMissingKwForItemSub>,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum AmbiguousMissingKwForItemSub {
+    #[suggestion(suggestion, applicability = "maybe-incorrect", code = "{snippet}!")]
+    SuggestMacro {
+        #[primary_span]
+        span: Span,
+        snippet: String,
+    },
+    #[help(help)]
+    HelpMacro,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_missing_trait_in_trait_impl)]
+pub(crate) struct MissingTraitInTraitImpl {
+    #[primary_span]
+    #[suggestion(suggestion_add_trait, code = " Trait ", applicability = "has-placeholders")]
+    pub span: Span,
+    #[suggestion(suggestion_remove_for, code = "", applicability = "maybe-incorrect")]
+    pub for_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_missing_for_in_trait_impl)]
+pub(crate) struct MissingForInTraitImpl {
+    #[primary_span]
+    #[suggestion(style = "short", code = " for ", applicability = "machine-applicable")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_expected_trait_in_trait_impl_found_type)]
+pub(crate) struct ExpectedTraitInTraitImplFoundType {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_bounds_not_allowed_on_trait_aliases)]
+pub(crate) struct BoundsNotAllowedOnTraitAliases {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_trait_alias_cannot_be_auto)]
+pub(crate) struct TraitAliasCannotBeAuto {
+    #[primary_span]
+    #[label(parse_trait_alias_cannot_be_auto)]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_trait_alias_cannot_be_unsafe)]
+pub(crate) struct TraitAliasCannotBeUnsafe {
+    #[primary_span]
+    #[label(parse_trait_alias_cannot_be_unsafe)]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_associated_static_item_not_allowed)]
+pub(crate) struct AssociatedStaticItemNotAllowed {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_extern_crate_name_with_dashes)]
+pub(crate) struct ExternCrateNameWithDashes {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sugg: ExternCrateNameWithDashesSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+pub(crate) struct ExternCrateNameWithDashesSugg {
+    #[suggestion_part(code = "_")]
+    pub dashes: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_extern_item_cannot_be_const)]
+#[note]
+pub(crate) struct ExternItemCannotBeConst {
+    #[primary_span]
+    pub ident_span: Span,
+    #[suggestion(code = "static ", applicability = "machine-applicable")]
+    pub const_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_const_global_cannot_be_mutable)]
+pub(crate) struct ConstGlobalCannotBeMutable {
+    #[primary_span]
+    #[label]
+    pub ident_span: Span,
+    #[suggestion(code = "static", applicability = "maybe-incorrect")]
+    pub const_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_missing_const_type)]
+pub(crate) struct MissingConstType {
+    #[primary_span]
+    #[suggestion(code = "{colon} <type>", applicability = "has-placeholders")]
+    pub span: Span,
+
+    pub kind: &'static str,
+    pub colon: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_enum_struct_mutually_exclusive)]
+pub(crate) struct EnumStructMutuallyExclusive {
+    #[primary_span]
+    #[suggestion(code = "enum", applicability = "machine-applicable")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+pub(crate) enum UnexpectedTokenAfterStructName {
+    #[diag(parse_unexpected_token_after_struct_name_found_reserved_identifier)]
+    ReservedIdentifier {
+        #[primary_span]
+        #[label(parse_unexpected_token_after_struct_name)]
+        span: Span,
+        token: Token,
+    },
+    #[diag(parse_unexpected_token_after_struct_name_found_keyword)]
+    Keyword {
+        #[primary_span]
+        #[label(parse_unexpected_token_after_struct_name)]
+        span: Span,
+        token: Token,
+    },
+    #[diag(parse_unexpected_token_after_struct_name_found_reserved_keyword)]
+    ReservedKeyword {
+        #[primary_span]
+        #[label(parse_unexpected_token_after_struct_name)]
+        span: Span,
+        token: Token,
+    },
+    #[diag(parse_unexpected_token_after_struct_name_found_doc_comment)]
+    DocComment {
+        #[primary_span]
+        #[label(parse_unexpected_token_after_struct_name)]
+        span: Span,
+        token: Token,
+    },
+    #[diag(parse_unexpected_token_after_struct_name_found_other)]
+    Other {
+        #[primary_span]
+        #[label(parse_unexpected_token_after_struct_name)]
+        span: Span,
+        token: Token,
+    },
+}
+
+impl UnexpectedTokenAfterStructName {
+    pub fn new(span: Span, token: Token) -> Self {
+        match TokenDescription::from_token(&token) {
+            Some(TokenDescription::ReservedIdentifier) => Self::ReservedIdentifier { span, token },
+            Some(TokenDescription::Keyword) => Self::Keyword { span, token },
+            Some(TokenDescription::ReservedKeyword) => Self::ReservedKeyword { span, token },
+            Some(TokenDescription::DocComment) => Self::DocComment { span, token },
+            None => Self::Other { span, token },
+        }
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_unexpected_self_in_generic_parameters)]
+#[note]
+pub(crate) struct UnexpectedSelfInGenericParameters {
+    #[primary_span]
+    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 {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub previous: Span,
+    #[suggestion(style = "verbose", code = ",", applicability = "maybe-incorrect")]
+    pub between: Span,
+}
+
+#[derive(Diagnostic)]
+pub(crate) enum UnexpectedNonterminal {
+    #[diag(parse_nonterminal_expected_item_keyword)]
+    Item(#[primary_span] Span),
+    #[diag(parse_nonterminal_expected_statement)]
+    Statement(#[primary_span] Span),
+    #[diag(parse_nonterminal_expected_ident)]
+    Ident {
+        #[primary_span]
+        span: Span,
+        token: Token,
+    },
+    #[diag(parse_nonterminal_expected_lifetime)]
+    Lifetime {
+        #[primary_span]
+        span: Span,
+        token: Token,
+    },
+}
+
+#[derive(Diagnostic)]
+pub(crate) enum TopLevelOrPatternNotAllowed {
+    #[diag(parse_or_pattern_not_allowed_in_let_binding)]
+    LetBinding {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        sub: Option<TopLevelOrPatternNotAllowedSugg>,
+    },
+    #[diag(parse_or_pattern_not_allowed_in_fn_parameters)]
+    FunctionParameter {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        sub: Option<TopLevelOrPatternNotAllowedSugg>,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum TopLevelOrPatternNotAllowedSugg {
+    #[suggestion(
+        parse_sugg_remove_leading_vert_in_pattern,
+        code = "{pat}",
+        applicability = "machine-applicable"
+    )]
+    RemoveLeadingVert {
+        #[primary_span]
+        span: Span,
+        pat: String,
+    },
+    #[suggestion(
+        parse_sugg_wrap_pattern_in_parens,
+        code = "({pat})",
+        applicability = "machine-applicable"
+    )]
+    WrapInParens {
+        #[primary_span]
+        span: Span,
+        pat: String,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_unexpected_vert_vert_before_function_parameter)]
+#[note(parse_note_pattern_alternatives_use_single_vert)]
+pub(crate) struct UnexpectedVertVertBeforeFunctionParam {
+    #[primary_span]
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_unexpected_vert_vert_in_pattern)]
+pub(crate) struct UnexpectedVertVertInPattern {
+    #[primary_span]
+    #[suggestion(code = "|", applicability = "machine-applicable")]
+    pub span: Span,
+    #[label(parse_label_while_parsing_or_pattern_here)]
+    pub start: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_trailing_vert_not_allowed)]
+pub(crate) struct TrailingVertNotAllowed {
+    #[primary_span]
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub span: Span,
+    #[label(parse_label_while_parsing_or_pattern_here)]
+    pub start: Option<Span>,
+    pub token: Token,
+    #[note(parse_note_pattern_alternatives_use_single_vert)]
+    pub note_double_vert: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_dotdotdot_rest_pattern)]
+pub(crate) struct DotDotDotRestPattern {
+    #[primary_span]
+    #[suggestion(style = "short", code = "..", applicability = "machine-applicable")]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_pattern_on_wrong_side_of_at)]
+pub(crate) struct PatternOnWrongSideOfAt {
+    #[primary_span]
+    #[suggestion(code = "{whole_pat}", applicability = "machine-applicable")]
+    pub whole_span: Span,
+    pub whole_pat: String,
+    #[label(label_pattern)]
+    pub pattern: Span,
+    #[label(label_binding)]
+    pub binding: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_expected_binding_left_of_at)]
+#[note]
+pub(crate) struct ExpectedBindingLeftOfAt {
+    #[primary_span]
+    pub whole_span: Span,
+    #[label(label_lhs)]
+    pub lhs: Span,
+    #[label(label_rhs)]
+    pub rhs: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_ambiguous_range_pattern)]
+pub(crate) struct AmbiguousRangePattern {
+    #[primary_span]
+    #[suggestion(code = "({pat})", applicability = "maybe-incorrect")]
+    pub span: Span,
+    pub pat: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_unexpected_lifetime_in_pattern)]
+pub(crate) struct UnexpectedLifetimeInPattern {
+    #[primary_span]
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub span: Span,
+    pub symbol: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_ref_mut_order_incorrect)]
+pub(crate) struct RefMutOrderIncorrect {
+    #[primary_span]
+    #[suggestion(code = "ref mut", applicability = "machine-applicable")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+pub(crate) enum InvalidMutInPattern {
+    #[diag(parse_mut_on_nested_ident_pattern)]
+    #[note(parse_note_mut_pattern_usage)]
+    NestedIdent {
+        #[primary_span]
+        #[suggestion(code = "{pat}", applicability = "machine-applicable")]
+        span: Span,
+        pat: String,
+    },
+    #[diag(parse_mut_on_non_ident_pattern)]
+    #[note(parse_note_mut_pattern_usage)]
+    NonIdent {
+        #[primary_span]
+        #[suggestion(code = "{pat}", applicability = "machine-applicable")]
+        span: Span,
+        pat: String,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_repeated_mut_in_pattern)]
+pub(crate) struct RepeatedMutInPattern {
+    #[primary_span]
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_dot_dot_dot_range_to_pattern_not_allowed)]
+pub(crate) struct DotDotDotRangeToPatternNotAllowed {
+    #[primary_span]
+    #[suggestion(style = "short", code = "..=", applicability = "machine-applicable")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_enum_pattern_instead_of_identifier)]
+pub(crate) struct EnumPatternInsteadOfIdentifier {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_dot_dot_dot_for_remaining_fields)]
+pub(crate) struct DotDotDotForRemainingFields {
+    #[primary_span]
+    #[suggestion(code = "..", style = "verbose", applicability = "machine-applicable")]
+    pub span: Span,
+    pub token_str: Cow<'static, str>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_expected_comma_after_pattern_field)]
+pub(crate) struct ExpectedCommaAfterPatternField {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_return_types_use_thin_arrow)]
+pub(crate) struct ReturnTypesUseThinArrow {
+    #[primary_span]
+    #[suggestion(style = "short", code = "->", applicability = "machine-applicable")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_need_plus_after_trait_object_lifetime)]
+pub(crate) struct NeedPlusAfterTraitObjectLifetime {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_expected_mut_or_const_in_raw_pointer_type)]
+pub(crate) struct ExpectedMutOrConstInRawPointerType {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code("mut ", "const "), applicability = "has-placeholders")]
+    pub after_asterisk: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_lifetime_after_mut)]
+pub(crate) struct LifetimeAfterMut {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = "&{snippet} mut", applicability = "maybe-incorrect")]
+    pub suggest_lifetime: Option<Span>,
+    pub snippet: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_dyn_after_mut)]
+pub(crate) struct DynAfterMut {
+    #[primary_span]
+    #[suggestion(code = "&mut dyn", applicability = "machine-applicable")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_fn_pointer_cannot_be_const)]
+pub(crate) struct FnPointerCannotBeConst {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    #[label]
+    pub qualifier: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_fn_pointer_cannot_be_async)]
+pub(crate) struct FnPointerCannotBeAsync {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    #[label]
+    pub qualifier: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_nested_c_variadic_type, code = "E0743")]
+pub(crate) struct NestedCVariadicType {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_invalid_dyn_keyword)]
+#[help]
+pub(crate) struct InvalidDynKeyword {
+    #[primary_span]
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_negative_bounds_not_supported)]
+pub(crate) struct NegativeBoundsNotSupported {
+    #[primary_span]
+    pub negative_bounds: Vec<Span>,
+    #[label]
+    pub last_span: Span,
+    #[subdiagnostic]
+    pub sub: Option<NegativeBoundsNotSupportedSugg>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+    suggestion,
+    style = "tool-only",
+    code = "{fixed}",
+    applicability = "machine-applicable"
+)]
+pub(crate) struct NegativeBoundsNotSupportedSugg {
+    #[primary_span]
+    pub bound_list: Span,
+    pub num_bounds: usize,
+    pub fixed: String,
+}
+
+#[derive(Subdiagnostic)]
+pub enum HelpUseLatestEdition {
+    #[help(parse_help_set_edition_cargo)]
+    #[note(parse_note_edition_guide)]
+    Cargo { edition: Edition },
+    #[help(parse_help_set_edition_standalone)]
+    #[note(parse_note_edition_guide)]
+    Standalone { edition: Edition },
+}
+
+impl HelpUseLatestEdition {
+    pub fn new() -> Self {
+        let edition = LATEST_STABLE_EDITION;
+        if std::env::var_os("CARGO").is_some() {
+            Self::Cargo { edition }
+        } else {
+            Self::Standalone { edition }
+        }
+    }
+}
index b97f22417cb7bdcc82482abf2a6314d4ff664c03..dbd3b76786f42c56d67f44aee2c6d5f588212baa 100644 (file)
@@ -469,6 +469,6 @@ mod size_asserts {
     use rustc_data_structures::static_assert_size;
     // tidy-alphabetical-start
     static_assert_size!(AttrWrapper, 16);
-    static_assert_size!(LazyAttrTokenStreamImpl, 144);
+    static_assert_size!(LazyAttrTokenStreamImpl, 120);
     // tidy-alphabetical-end
 }
index f4c08031bcca08c15542d6eb326d56bd07e54749..cd9d85b1d919c9c3f45541e83a9223857550be9c 100644 (file)
@@ -2030,7 +2030,7 @@ pub(super) fn parameter_without_type(
     }
 
     pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
-        let pat = self.parse_pat_no_top_alt(Some("argument name"))?;
+        let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName))?;
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
 
@@ -2394,10 +2394,10 @@ pub fn dummy_const_arg_needs_braces(
 
     /// Some special error handling for the "top-level" patterns in a match arm,
     /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
-    pub(crate) fn maybe_recover_colon_colon_in_pat_typo_or_anon_enum(
+    pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
         &mut self,
         mut first_pat: P<Pat>,
-        expected: Expected,
+        expected: Option<Expected>,
     ) -> P<Pat> {
         if token::Colon != self.token.kind {
             return first_pat;
@@ -2435,8 +2435,9 @@ pub(crate) fn maybe_recover_colon_colon_in_pat_typo_or_anon_enum(
         // Create error for "unexpected `:`".
         match self.expected_one_of_not_found(&[], &[]) {
             Err(mut err) => {
-                snapshot_pat.bump(); // Skip the `:`.
-                snapshot_type.bump(); // Skip the `:`.
+                // Skip the `:`.
+                snapshot_pat.bump();
+                snapshot_type.bump();
                 match snapshot_pat.parse_pat_no_top_alt(expected) {
                     Err(inner_err) => {
                         inner_err.cancel();
index dcc3059a7f44ca5d7838bf4873d76ae511833a33..c37808f8c3d19b244e01abe806ef5f50e59ccba9 100644 (file)
@@ -1,29 +1,11 @@
 use super::diagnostics::SnapshotParser;
-use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED};
+use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{
     AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
     SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken,
 };
-use crate::errors::{
-    ArrayBracketsInsteadOfSpaces, ArrayBracketsInsteadOfSpacesSugg, AsyncMoveOrderIncorrect,
-    BracesForStructLiteral, CatchAfterTry, CommaAfterBaseStruct, ComparisonInterpretedAsGeneric,
-    ComparisonOrShiftInterpretedAsGenericSugg, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
-    ExpectedElseBlock, ExpectedEqForLetExpr, ExpectedExpressionFoundLet,
-    FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt,
-    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;
@@ -39,8 +21,8 @@
 use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{
-    Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult,
-    StashKey,
+    AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
+    PResult, StashKey,
 };
 use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded};
 use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
@@ -243,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,
@@ -261,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(),
@@ -279,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();
             }
@@ -419,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),
@@ -446,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)
             }
@@ -580,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) {
@@ -632,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)
     }
@@ -660,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
@@ -738,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,
                                 });
@@ -763,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,
@@ -917,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 ]`.
@@ -1211,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))
@@ -1285,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);
@@ -1499,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 {
@@ -1549,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,
@@ -1561,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,
@@ -1569,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,
@@ -1605,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(),
                 });
@@ -1621,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(),
@@ -1670,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)
     }
@@ -1718,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(),
                 },
@@ -1840,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);
@@ -1901,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(),
                 });
@@ -1962,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,
+            });
         }
     }
 
@@ -2002,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,
                     },
@@ -2050,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));
@@ -2076,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),
             });
@@ -2108,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 };
@@ -2140,7 +2131,7 @@ fn parse_closure_expr(&mut self) -> PResult<'a, P<Expr>> {
         }
 
         if self.token.kind == TokenKind::Semi
-            && matches!(self.token_cursor.frame.delim_sp, Some((Delimiter::Parenthesis, _)))
+            && matches!(self.token_cursor.stack.last(), Some((_, Delimiter::Parenthesis, _)))
             && self.may_recover()
         {
             // It is likely that the closure body is a block but where the
@@ -2180,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)
@@ -2221,7 +2212,7 @@ fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
         let lo = self.token.span;
         let attrs = self.parse_outer_attributes()?;
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
-            let pat = this.parse_pat_no_top_alt(PARAM_EXPECTED)?;
+            let pat = this.parse_pat_no_top_alt(Some(Expected::ParameterName))?;
             let ty = if this.eat(&token::Colon) {
                 this.parse_ty()?
             } else {
@@ -2258,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),
                     });
@@ -2290,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 });
+                    .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,
@@ -2350,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
@@ -2362,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,
             });
@@ -2397,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,
@@ -2437,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,
@@ -2450,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(())
             }
@@ -2480,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);
@@ -2491,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).
@@ -2600,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)
@@ -2716,6 +2722,14 @@ fn check_let_expr(expr: &Expr) -> (bool, bool) {
                     );
                     err.emit();
                     this.bump();
+                } else if matches!(
+                    (&this.prev_token.kind, &this.token.kind),
+                    (token::DotDotEq, token::Gt)
+                ) {
+                    // `error_inclusive_range_match_arrow` handles cases like `0..=> {}`,
+                    // so we supress the error here
+                    err.delay_as_bug();
+                    this.bump();
                 } else {
                     return Err(err);
                 }
@@ -2793,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);
@@ -2825,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);
@@ -2901,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(),
                     },
@@ -2926,8 +2940,8 @@ pub(super) fn parse_struct_fields(
 
         let mut async_block_err = |e: &mut Diagnostic, span: Span| {
             recover_async = true;
-            e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later");
-            e.help_use_latest_edition();
+            errors::AsyncBlockIn2015 { span }.add_to_diagnostic(e);
+            errors::HelpUseLatestEdition::new().add_to_diagnostic(e);
         };
 
         while self.token != token::CloseDelim(close_delim) {
@@ -3071,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,
         });
@@ -3084,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
@@ -3152,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 8ba811715d80db6dc9bbf88837990d629e721a29..23f49ec55a18ddda7a413b3de172b7df7b05cc01 100644 (file)
@@ -1,4 +1,8 @@
-use crate::errors::{WhereClauseBeforeTupleStructBody, WhereClauseBeforeTupleStructBodySugg};
+use crate::errors::{
+    MultipleWhereClauses, UnexpectedDefaultValueForLifetimeInGenericParameters,
+    UnexpectedSelfInGenericParameters, WhereClauseBeforeTupleStructBody,
+    WhereClauseBeforeTupleStructBodySugg,
+};
 
 use super::{ForceCollect, Parser, TrailingToken};
 
@@ -127,12 +131,9 @@ pub(super) fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericPar
                     if this.eat_keyword_noexpect(kw::SelfUpper) {
                         // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
                         // as if `Self` never existed.
-                        this.struct_span_err(
-                            this.prev_token.span,
-                            "unexpected keyword `Self` in generic parameters",
-                        )
-                        .note("you cannot use `Self` as a generic parameter because it is reserved for associated items")
-                        .emit();
+                        this.sess.emit_err(UnexpectedSelfInGenericParameters {
+                            span: this.prev_token.span,
+                        });
 
                         this.eat(&token::Comma);
                     }
@@ -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,
@@ -329,16 +344,11 @@ fn parse_where_clause_common(
             let ate_comma = self.eat(&token::Comma);
 
             if self.eat_keyword_noexpect(kw::Where) {
-                let msg = "cannot define duplicate `where` clauses on an item";
-                let mut err = self.struct_span_err(self.token.span, msg);
-                err.span_label(pred_lo, "previous `where` clause starts here");
-                err.span_suggestion_verbose(
-                    prev_token.shrink_to_hi().to(self.prev_token.span),
-                    "consider joining the two `where` clauses into one",
-                    ",",
-                    Applicability::MaybeIncorrect,
-                );
-                err.emit();
+                self.sess.emit_err(MultipleWhereClauses {
+                    span: self.token.span,
+                    previous: pred_lo,
+                    between: prev_token.shrink_to_hi().to(self.prev_token.span),
+                });
             } else if !ate_comma {
                 break;
             }
index 53680a82bdc2e11825a278169dab577cb8aa8ddf..628e9d88cf1df27451b7811dc010fc9b08ed5cdd 100644 (file)
@@ -1,4 +1,13 @@
-use crate::errors::{DocCommentDoesNotDocumentAnything, UseEmptyBlockNotSemi};
+use crate::errors::{
+    AmbiguousMissingKwForItemSub, AssociatedStaticItemNotAllowed, AsyncFnIn2015,
+    BoundsNotAllowedOnTraitAliases, ConstGlobalCannotBeMutable, ConstLetMutuallyExclusive,
+    DefaultNotFollowedByItem, DocCommentDoesNotDocumentAnything, EnumStructMutuallyExclusive,
+    ExpectedTraitInTraitImplFoundType, ExternCrateNameWithDashes, ExternCrateNameWithDashesSugg,
+    ExternItemCannotBeConst, HelpUseLatestEdition, MissingConstType, MissingForInTraitImpl,
+    MissingKeywordForItemDefinition, MissingTraitInTraitImpl, SelfArgumentPointer,
+    TraitAliasCannotBeAuto, TraitAliasCannotBeUnsafe, UnexpectedTokenAfterStructName,
+    UseEmptyBlockNotSemi, VisibilityNotFollowedByItem,
+};
 
 use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
 use rustc_ast::{MacCall, MacDelimiter};
 use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability, IntoDiagnostic, PResult, StashKey};
+use rustc_errors::{
+    struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult,
+    StashKey,
+};
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::lev_distance;
 use rustc_span::source_map::{self, Span};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::DUMMY_SP;
+use std::fmt::Write;
 use std::mem;
 use thin_vec::ThinVec;
 
@@ -163,35 +176,18 @@ fn parse_item_common_(
         }
 
         // At this point, we have failed to parse an item.
-        self.error_on_unmatched_vis(&vis);
-        self.error_on_unmatched_defaultness(def);
-        if !attrs_allowed {
-            self.recover_attrs_no_item(&attrs)?;
+        if !matches!(vis.kind, VisibilityKind::Inherited) {
+            self.sess.emit_err(VisibilityNotFollowedByItem { span: vis.span, vis });
         }
-        Ok(None)
-    }
 
-    /// Error in-case a non-inherited visibility was parsed but no item followed.
-    fn error_on_unmatched_vis(&self, vis: &Visibility) {
-        if let VisibilityKind::Inherited = vis.kind {
-            return;
+        if let Defaultness::Default(span) = def {
+            self.sess.emit_err(DefaultNotFollowedByItem { span });
         }
-        let vs = pprust::vis_to_string(&vis);
-        let vs = vs.trim_end();
-        self.struct_span_err(vis.span, &format!("visibility `{vs}` is not followed by an item"))
-            .span_label(vis.span, "the visibility")
-            .help(&format!("you likely meant to define an item, e.g., `{vs} fn foo() {{}}`"))
-            .emit();
-    }
 
-    /// Error in-case a `default` was parsed but no item followed.
-    fn error_on_unmatched_defaultness(&self, def: Defaultness) {
-        if let Defaultness::Default(sp) = def {
-            self.struct_span_err(sp, "`default` is not followed by an item")
-                .span_label(sp, "the `default` qualifier")
-                .note("only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`")
-                .emit();
+        if !attrs_allowed {
+            self.recover_attrs_no_item(&attrs)?;
         }
+        Ok(None)
     }
 
     /// Error in-case `default` was parsed in an in-appropriate context.
@@ -384,86 +380,72 @@ fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> {
         let sp = self.prev_token.span.between(self.token.span);
         let full_sp = self.prev_token.span.to(self.token.span);
         let ident_sp = self.token.span;
-        if self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace)) {
+
+        let ident = if self.look_ahead(1, |t| {
+            [
+                token::Lt,
+                token::OpenDelim(Delimiter::Brace),
+                token::OpenDelim(Delimiter::Parenthesis),
+            ]
+            .contains(&t.kind)
+        }) {
+            self.parse_ident().unwrap()
+        } else {
+            return Ok(());
+        };
+
+        let mut found_generics = false;
+        if self.check(&token::Lt) {
+            found_generics = true;
+            self.eat_to_tokens(&[&token::Gt]);
+            self.bump(); // `>`
+        }
+
+        let err = if self.check(&token::OpenDelim(Delimiter::Brace)) {
             // possible public struct definition where `struct` was forgotten
-            let ident = self.parse_ident().unwrap();
-            let msg = format!("add `struct` here to parse `{ident}` as a public struct");
-            let mut err = self.struct_span_err(sp, "missing `struct` for struct definition");
-            err.span_suggestion_short(
-                sp,
-                &msg,
-                " struct ",
-                Applicability::MaybeIncorrect, // speculative
-            );
-            Err(err)
-        } else if self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis)) {
-            let ident = self.parse_ident().unwrap();
+            Some(MissingKeywordForItemDefinition::Struct { span: sp, ident })
+        } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
+            // possible public function or tuple struct definition where `fn`/`struct` was
+            // forgotten
             self.bump(); // `(`
-            let kw_name = self.recover_first_param();
+            let is_method = self.recover_self_param();
+
             self.consume_block(Delimiter::Parenthesis, ConsumeClosingDelim::Yes);
-            let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) {
+
+            let err = if self.check(&token::RArrow)
+                || self.check(&token::OpenDelim(Delimiter::Brace))
+            {
                 self.eat_to_tokens(&[&token::OpenDelim(Delimiter::Brace)]);
                 self.bump(); // `{`
-                ("fn", kw_name, false)
-            } else if self.check(&token::OpenDelim(Delimiter::Brace)) {
-                self.bump(); // `{`
-                ("fn", kw_name, false)
-            } else if self.check(&token::Colon) {
-                let kw = "struct";
-                (kw, kw, false)
-            } else {
-                ("fn` or `struct", "function or struct", true)
-            };
-
-            let msg = format!("missing `{kw}` for {kw_name} definition");
-            let mut err = self.struct_span_err(sp, &msg);
-            if !ambiguous {
                 self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
-                let suggestion =
-                    format!("add `{kw}` here to parse `{ident}` as a public {kw_name}");
-                err.span_suggestion_short(
-                    sp,
-                    &suggestion,
-                    format!(" {kw} "),
-                    Applicability::MachineApplicable,
-                );
-            } else if let Ok(snippet) = self.span_to_snippet(ident_sp) {
-                err.span_suggestion(
-                    full_sp,
-                    "if you meant to call a macro, try",
-                    format!("{}!", snippet),
-                    // this is the `ambiguous` conditional branch
-                    Applicability::MaybeIncorrect,
-                );
-            } else {
-                err.help(
-                    "if you meant to call a macro, remove the `pub` \
-                              and add a trailing `!` after the identifier",
-                );
-            }
-            Err(err)
-        } else if self.look_ahead(1, |t| *t == token::Lt) {
-            let ident = self.parse_ident().unwrap();
-            self.eat_to_tokens(&[&token::Gt]);
-            self.bump(); // `>`
-            let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(Delimiter::Parenthesis)) {
-                ("fn", self.recover_first_param(), false)
-            } else if self.check(&token::OpenDelim(Delimiter::Brace)) {
-                ("struct", "struct", false)
+                if is_method {
+                    MissingKeywordForItemDefinition::Method { span: sp, ident }
+                } else {
+                    MissingKeywordForItemDefinition::Function { span: sp, ident }
+                }
+            } else if self.check(&token::Semi) {
+                MissingKeywordForItemDefinition::Struct { span: sp, ident }
             } else {
-                ("fn` or `struct", "function or struct", true)
+                MissingKeywordForItemDefinition::Ambiguous {
+                    span: sp,
+                    subdiag: if found_generics {
+                        None
+                    } else if let Ok(snippet) = self.span_to_snippet(ident_sp) {
+                        Some(AmbiguousMissingKwForItemSub::SuggestMacro { span: full_sp, snippet })
+                    } else {
+                        Some(AmbiguousMissingKwForItemSub::HelpMacro)
+                    },
+                }
             };
-            let msg = format!("missing `{kw}` for {kw_name} definition");
-            let mut err = self.struct_span_err(sp, &msg);
-            if !ambiguous {
-                err.span_suggestion_short(
-                    sp,
-                    &format!("add `{kw}` here to parse `{ident}` as a public {kw_name}"),
-                    format!(" {} ", kw),
-                    Applicability::MachineApplicable,
-                );
-            }
-            Err(err)
+            Some(err)
+        } else if found_generics {
+            Some(MissingKeywordForItemDefinition::Ambiguous { span: sp, subdiag: None })
+        } else {
+            None
+        };
+
+        if let Some(err) = err {
+            Err(err.into_diagnostic(&self.sess.span_diagnostic))
         } else {
             Ok(())
         }
@@ -512,16 +494,13 @@ fn recover_attrs_no_item(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> {
         let mut err = self.struct_span_err(end.span, msg);
         if end.is_doc_comment() {
             err.span_label(end.span, "this doc comment doesn't document anything");
-        }
-        if end.meta_kind().is_some() {
-            if self.token.kind == TokenKind::Semi {
-                err.span_suggestion_verbose(
-                    self.token.span,
-                    "consider removing this semicolon",
-                    "",
-                    Applicability::MaybeIncorrect,
-                );
-            }
+        } else if self.token.kind == TokenKind::Semi {
+            err.span_suggestion_verbose(
+                self.token.span,
+                "consider removing this semicolon",
+                "",
+                Applicability::MaybeIncorrect,
+            );
         }
         if let [.., penultimate, _] = attrs {
             err.span_label(start.span.to(penultimate.span), "other attributes here");
@@ -588,20 +567,9 @@ fn parse_item_impl(
         let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt)
         {
             let span = self.prev_token.span.between(self.token.span);
-            self.struct_span_err(span, "missing trait in a trait impl")
-                .span_suggestion(
-                    span,
-                    "add a trait here",
-                    " Trait ",
-                    Applicability::HasPlaceholders,
-                )
-                .span_suggestion(
-                    span.to(self.token.span),
-                    "for an inherent impl, drop this `for`",
-                    "",
-                    Applicability::MaybeIncorrect,
-                )
-                .emit();
+            self.sess
+                .emit_err(MissingTraitInTraitImpl { span, for_span: span.to(self.token.span) });
+
             P(Ty {
                 kind: TyKind::Path(None, err_path(span)),
                 span,
@@ -634,14 +602,7 @@ fn parse_item_impl(
             Some(ty_second) => {
                 // impl Trait for Type
                 if !has_for {
-                    self.struct_span_err(missing_for_span, "missing `for` in a trait impl")
-                        .span_suggestion_short(
-                            missing_for_span,
-                            "add `for` here",
-                            " for ",
-                            Applicability::MachineApplicable,
-                        )
-                        .emit();
+                    self.sess.emit_err(MissingForInTraitImpl { span: missing_for_span });
                 }
 
                 let ty_first = ty_first.into_inner();
@@ -649,7 +610,8 @@ fn parse_item_impl(
                     // This notably includes paths passed through `ty` macro fragments (#46438).
                     TyKind::Path(None, path) => path,
                     _ => {
-                        self.struct_span_err(ty_first.span, "expected a trait, found type").emit();
+                        self.sess
+                            .emit_err(ExpectedTraitInTraitImplFoundType { span: ty_first.span });
                         err_path(ty_first.span)
                     }
                 };
@@ -783,6 +745,7 @@ fn parse_item_list<T>(
     fn recover_doc_comment_before_brace(&mut self) -> bool {
         if let token::DocComment(..) = self.token.kind {
             if self.look_ahead(1, |tok| tok == &token::CloseDelim(Delimiter::Brace)) {
+                // FIXME: merge with `DocCommentDoesNotDocumentAnything` (E0585)
                 struct_span_err!(
                     self.diagnostic(),
                     self.token.span,
@@ -849,7 +812,7 @@ fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, Ite
             // It's a trait alias.
             if had_colon {
                 let span = span_at_colon.to(span_before_eq);
-                self.struct_span_err(span, "bounds are not allowed on trait aliases").emit();
+                self.sess.emit_err(BoundsNotAllowedOnTraitAliases { span });
             }
 
             let bounds = self.parse_generic_bounds(None)?;
@@ -858,12 +821,10 @@ fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, Ite
 
             let whole_span = lo.to(self.prev_token.span);
             if is_auto == IsAuto::Yes {
-                let msg = "trait aliases cannot be `auto`";
-                self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit();
+                self.sess.emit_err(TraitAliasCannotBeAuto { span: whole_span });
             }
             if let Unsafe::Yes(_) = unsafety {
-                let msg = "trait aliases cannot be `unsafe`";
-                self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit();
+                self.sess.emit_err(TraitAliasCannotBeUnsafe { span: whole_span });
             }
 
             self.sess.gated_spans.gate(sym::trait_alias, whole_span);
@@ -909,8 +870,7 @@ fn parse_assoc_item(
                     Ok(kind) => kind,
                     Err(kind) => match kind {
                         ItemKind::Static(a, _, b) => {
-                            self.struct_span_err(span, "associated `static` items are not allowed")
-                                .emit();
+                            self.sess.emit_err(AssociatedStaticItemNotAllowed { span });
                             AssocItemKind::Const(Defaultness::Final, a, b)
                         }
                         _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"),
@@ -1084,41 +1044,37 @@ fn parse_item_extern_crate(&mut self) -> PResult<'a, ItemInfo> {
     }
 
     fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, Ident> {
-        let error_msg = "crate name using dashes are not valid in `extern crate` statements";
-        let suggestion_msg = "if the original crate name uses dashes you need to use underscores \
-                              in the code";
-        let mut ident = if self.token.is_keyword(kw::SelfLower) {
+        let ident = if self.token.is_keyword(kw::SelfLower) {
             self.parse_path_segment_ident()
         } else {
             self.parse_ident()
         }?;
-        let mut idents = vec![];
-        let mut replacement = vec![];
-        let mut fixed_crate_name = false;
-        // Accept `extern crate name-like-this` for better diagnostics.
+
         let dash = token::BinOp(token::BinOpToken::Minus);
-        if self.token == dash {
-            // Do not include `-` as part of the expected tokens list.
-            while self.eat(&dash) {
-                fixed_crate_name = true;
-                replacement.push((self.prev_token.span, "_".to_string()));
-                idents.push(self.parse_ident()?);
-            }
+        if self.token != dash {
+            return Ok(ident);
         }
-        if fixed_crate_name {
-            let fixed_name_sp = ident.span.to(idents.last().unwrap().span);
-            let mut fixed_name = ident.name.to_string();
-            for part in idents {
-                fixed_name.push_str(&format!("_{}", part.name));
-            }
-            ident = Ident::from_str_and_span(&fixed_name, fixed_name_sp);
 
-            self.struct_span_err(fixed_name_sp, error_msg)
-                .span_label(fixed_name_sp, "dash-separated idents are not valid")
-                .multipart_suggestion(suggestion_msg, replacement, Applicability::MachineApplicable)
-                .emit();
+        // Accept `extern crate name-like-this` for better diagnostics.
+        let mut dashes = vec![];
+        let mut idents = vec![];
+        while self.eat(&dash) {
+            dashes.push(self.prev_token.span);
+            idents.push(self.parse_ident()?);
         }
-        Ok(ident)
+
+        let fixed_name_sp = ident.span.to(idents.last().unwrap().span);
+        let mut fixed_name = ident.name.to_string();
+        for part in idents {
+            write!(fixed_name, "_{}", part.name).unwrap();
+        }
+
+        self.sess.emit_err(ExternCrateNameWithDashes {
+            span: fixed_name_sp,
+            sugg: ExternCrateNameWithDashesSugg { dashes },
+        });
+
+        Ok(Ident::from_str_and_span(&fixed_name, fixed_name_sp))
     }
 
     /// Parses `extern` for foreign ABIs modules.
@@ -1166,7 +1122,10 @@ pub fn parse_foreign_item(
                     Ok(kind) => kind,
                     Err(kind) => match kind {
                         ItemKind::Const(_, a, b) => {
-                            self.error_on_foreign_const(span, ident);
+                            self.sess.emit_err(ExternItemCannotBeConst {
+                                ident_span: ident.span,
+                                const_span: span.with_hi(ident.span.lo()),
+                            });
                             ForeignItemKind::Static(a, Mutability::Not, b)
                         }
                         _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"),
@@ -1178,6 +1137,7 @@ pub fn parse_foreign_item(
     }
 
     fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &str) -> Option<T> {
+        // FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`)
         let span = self.sess.source_map().guess_head_span(span);
         let descr = kind.descr();
         self.struct_span_err(span, &format!("{descr} is not supported in {ctx}"))
@@ -1186,18 +1146,6 @@ fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &str) -> Opti
         None
     }
 
-    fn error_on_foreign_const(&self, span: Span, ident: Ident) {
-        self.struct_span_err(ident.span, "extern items cannot be `const`")
-            .span_suggestion(
-                span.with_hi(ident.span.lo()),
-                "try using a static value",
-                "static ",
-                Applicability::MachineApplicable,
-            )
-            .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html")
-            .emit();
-    }
-
     fn is_unsafe_foreign_mod(&self) -> bool {
         self.token.is_keyword(kw::Unsafe)
             && self.is_keyword_ahead(1, &[kw::Extern])
@@ -1225,25 +1173,10 @@ fn is_static_global(&mut self) -> bool {
     fn recover_const_mut(&mut self, const_span: Span) {
         if self.eat_keyword(kw::Mut) {
             let span = self.prev_token.span;
-            self.struct_span_err(span, "const globals cannot be mutable")
-                .span_label(span, "cannot be mutable")
-                .span_suggestion(
-                    const_span,
-                    "you might want to declare a static instead",
-                    "static",
-                    Applicability::MaybeIncorrect,
-                )
-                .emit();
+            self.sess.emit_err(ConstGlobalCannotBeMutable { ident_span: span, const_span });
         } else if self.eat_keyword(kw::Let) {
             let span = self.prev_token.span;
-            self.struct_span_err(const_span.to(span), "`const` and `let` are mutually exclusive")
-                .span_suggestion(
-                    const_span.to(span),
-                    "remove `let`",
-                    "const",
-                    Applicability::MaybeIncorrect,
-                )
-                .emit();
+            self.sess.emit_err(ConstLetMutuallyExclusive { span: const_span.to(span) });
         }
     }
 
@@ -1328,13 +1261,8 @@ fn recover_missing_const_type(&mut self, colon_present: bool, m: Option<Mutabili
         };
 
         let span = self.prev_token.span.shrink_to_hi();
-        let mut err = self.struct_span_err(span, &format!("missing type for `{kind}` item"));
-        err.span_suggestion(
-            span,
-            "provide a type for the item",
-            format!("{colon} <type>"),
-            Applicability::HasPlaceholders,
-        );
+        let err: DiagnosticBuilder<'_, ErrorGuaranteed> =
+            MissingConstType { span, colon, kind }.into_diagnostic(&self.sess.span_diagnostic);
         err.stash(span, StashKey::ItemNoType);
 
         // The user intended that the type be inferred,
@@ -1346,18 +1274,12 @@ fn recover_missing_const_type(&mut self, colon_present: bool, m: Option<Mutabili
     fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> {
         if self.token.is_keyword(kw::Struct) {
             let span = self.prev_token.span.to(self.token.span);
-            let mut err = self.struct_span_err(span, "`enum` and `struct` are mutually exclusive");
-            err.span_suggestion(
-                span,
-                "replace `enum struct` with",
-                "enum",
-                Applicability::MachineApplicable,
-            );
+            let err = EnumStructMutuallyExclusive { span };
             if self.look_ahead(1, |t| t.is_ident()) {
                 self.bump();
-                err.emit();
+                self.sess.emit_err(err);
             } else {
-                return Err(err);
+                return Err(err.into_diagnostic(&self.sess.span_diagnostic));
             }
         }
 
@@ -1493,13 +1415,8 @@ fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> {
             self.expect_semi()?;
             body
         } else {
-            let token_str = super::token_descr(&self.token);
-            let msg = &format!(
-                "expected `where`, `{{`, `(`, or `;` after struct name, found {token_str}"
-            );
-            let mut err = self.struct_span_err(self.token.span, msg);
-            err.span_label(self.token.span, "expected `where`, `{`, `(`, or `;` after struct name");
-            return Err(err);
+            let err = UnexpectedTokenAfterStructName::new(self.token.span, self.token.clone());
+            return Err(err.into_diagnostic(&self.sess.span_diagnostic));
         };
 
         Ok((class_name, ItemKind::Struct(vdata, generics)))
@@ -2330,7 +2247,9 @@ pub(super) fn parse_fn_front_matter(
         let ext = self.parse_extern(case);
 
         if let Async::Yes { span, .. } = asyncness {
-            self.ban_async_in_2015(span);
+            if span.is_rust_2015() {
+                self.sess.emit_err(AsyncFnIn2015 { span, help: HelpUseLatestEdition::new() });
+            }
         }
 
         if !self.eat_keyword_case(kw::Fn, case) {
@@ -2440,17 +2359,6 @@ enum WrongKw {
         Ok(FnHeader { constness, unsafety, asyncness, ext })
     }
 
-    /// We are parsing `async fn`. If we are on Rust 2015, emit an error.
-    fn ban_async_in_2015(&self, span: Span) {
-        if span.rust_2015() {
-            let diag = self.diagnostic();
-            struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015")
-                .span_label(span, "to use `async fn`, switch to Rust 2018 or later")
-                .help_use_latest_edition()
-                .emit();
-        }
-    }
-
     /// Parses the parameter list and result type of a function declaration.
     pub(super) fn parse_fn_decl(
         &mut self,
@@ -2593,9 +2501,7 @@ fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
         };
         // Recover for the grammar `*self`, `*const self`, and `*mut self`.
         let recover_self_ptr = |this: &mut Self| {
-            let msg = "cannot pass `self` by raw pointer";
-            let span = this.token.span;
-            this.struct_span_err(span, msg).span_label(span, msg).emit();
+            self.sess.emit_err(SelfArgumentPointer { span: this.token.span });
 
             Ok((SelfKind::Value(Mutability::Not), expect_self_ident(this), this.prev_token.span))
         };
@@ -2676,14 +2582,14 @@ fn is_named_param(&self) -> bool {
             && self.look_ahead(offset + 1, |t| t == &token::Colon)
     }
 
-    fn recover_first_param(&mut self) -> &'static str {
+    fn recover_self_param(&mut self) -> bool {
         match self
             .parse_outer_attributes()
             .and_then(|_| self.parse_self_param())
             .map_err(|e| e.cancel())
         {
-            Ok(Some(_)) => "method",
-            _ => "function",
+            Ok(Some(_)) => true,
+            _ => false,
         }
     }
 }
index ffb23b50a160de4101fb021faff9b6af54166b4c..0cb88f3c3a91697726fd3cde44b7774a7cea8c3d 100644 (file)
@@ -19,9 +19,8 @@
 
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind};
-use rustc_ast::tokenstream::AttributesData;
-use rustc_ast::tokenstream::{self, DelimSpan, Spacing};
-use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_ast::tokenstream::{AttributesData, DelimSpan, Spacing};
+use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
 use rustc_ast::util::case::Case;
 use rustc_ast::AttrId;
 use rustc_ast::DUMMY_NODE_ID;
@@ -168,7 +167,7 @@ pub struct Parser<'a> {
 // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
 // it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Parser<'_>, 336);
+rustc_data_structures::static_assert_size!(Parser<'_>, 312);
 
 /// Stores span information about a closure.
 #[derive(Clone)]
@@ -221,18 +220,27 @@ fn drop(&mut self) {
     }
 }
 
+/// Iterator over a `TokenStream` that produces `Token`s. It's a bit odd that
+/// we (a) lex tokens into a nice tree structure (`TokenStream`), and then (b)
+/// use this type to emit them as a linear sequence. But a linear sequence is
+/// what the parser expects, for the most part.
 #[derive(Clone)]
 struct TokenCursor {
-    // The current (innermost) frame. `frame` and `stack` could be combined,
-    // but it's faster to have them separately to access `frame` directly
-    // rather than via something like `stack.last().unwrap()` or
-    // `stack[stack.len() - 1]`.
-    frame: TokenCursorFrame,
-    // Additional frames that enclose `frame`.
-    stack: Vec<TokenCursorFrame>,
+    // Cursor for the current (innermost) token stream. The delimiters for this
+    // token stream are found in `self.stack.last()`; when that is `None` then
+    // we are in the outermost token stream which never has delimiters.
+    tree_cursor: TokenTreeCursor,
+
+    // Token streams surrounding the current one. The delimiters for stack[n]'s
+    // tokens are in `stack[n-1]`. `stack[0]` (when present) has no delimiters
+    // because it's the outermost token stream which never has delimiters.
+    stack: Vec<(TokenTreeCursor, Delimiter, DelimSpan)>,
+
     desugar_doc_comments: bool,
+
     // Counts the number of calls to `{,inlined_}next`.
     num_next_calls: usize,
+
     // During parsing, we may sometimes need to 'unglue' a
     // glued token into two component tokens
     // (e.g. '>>' into '>' and '>), so that the parser
@@ -257,18 +265,6 @@ struct TokenCursor {
     break_last_token: bool,
 }
 
-#[derive(Clone)]
-struct TokenCursorFrame {
-    delim_sp: Option<(Delimiter, DelimSpan)>,
-    tree_cursor: tokenstream::Cursor,
-}
-
-impl TokenCursorFrame {
-    fn new(delim_sp: Option<(Delimiter, DelimSpan)>, tts: TokenStream) -> Self {
-        TokenCursorFrame { delim_sp, tree_cursor: tts.into_trees() }
-    }
-}
-
 impl TokenCursor {
     fn next(&mut self, desugar_doc_comments: bool) -> (Token, Spacing) {
         self.inlined_next(desugar_doc_comments)
@@ -281,38 +277,47 @@ fn inlined_next(&mut self, desugar_doc_comments: bool) -> (Token, Spacing) {
             // FIXME: we currently don't return `Delimiter` open/close delims. To fix #67062 we will
             // need to, whereupon the `delim != Delimiter::Invisible` conditions below can be
             // removed.
-            if let Some(tree) = self.frame.tree_cursor.next_ref() {
+            if let Some(tree) = self.tree_cursor.next_ref() {
                 match tree {
                     &TokenTree::Token(ref token, spacing) => match (desugar_doc_comments, token) {
                         (true, &Token { kind: token::DocComment(_, attr_style, data), span }) => {
-                            return self.desugar(attr_style, data, span);
+                            let desugared = self.desugar(attr_style, data, span);
+                            self.tree_cursor.replace_prev_and_rewind(desugared);
+                            // Continue to get the first token of the desugared doc comment.
+                        }
+                        _ => {
+                            debug_assert!(!matches!(
+                                token.kind,
+                                token::OpenDelim(_) | token::CloseDelim(_)
+                            ));
+                            return (token.clone(), spacing);
                         }
-                        _ => return (token.clone(), spacing),
                     },
                     &TokenTree::Delimited(sp, delim, ref tts) => {
-                        // Set `open_delim` to true here because we deal with it immediately.
-                        let frame = TokenCursorFrame::new(Some((delim, sp)), tts.clone());
-                        self.stack.push(mem::replace(&mut self.frame, frame));
+                        let trees = tts.clone().into_trees();
+                        self.stack.push((mem::replace(&mut self.tree_cursor, trees), delim, sp));
                         if delim != Delimiter::Invisible {
                             return (Token::new(token::OpenDelim(delim), sp.open), Spacing::Alone);
                         }
                         // No open delimiter to return; continue on to the next iteration.
                     }
                 };
-            } else if let Some(frame) = self.stack.pop() {
-                if let Some((delim, span)) = self.frame.delim_sp && delim != Delimiter::Invisible {
-                    self.frame = frame;
+            } else if let Some((tree_cursor, delim, span)) = self.stack.pop() {
+                // We have exhausted this token stream. Move back to its parent token stream.
+                self.tree_cursor = tree_cursor;
+                if delim != Delimiter::Invisible {
                     return (Token::new(token::CloseDelim(delim), span.close), Spacing::Alone);
                 }
-                self.frame = frame;
                 // No close delimiter to return; continue on to the next iteration.
             } else {
+                // We have exhausted the outermost token stream.
                 return (Token::new(token::Eof, DUMMY_SP), Spacing::Alone);
             }
         }
     }
 
-    fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> (Token, Spacing) {
+    // Desugar a doc comment into something like `#[doc = r"foo"]`.
+    fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> Vec<TokenTree> {
         // Searches for the occurrences of `"#*` and returns the minimum number of `#`s
         // required to wrap the text. E.g.
         // - `abc d` is wrapped as `r"abc d"` (num_of_hashes = 0)
@@ -346,27 +351,15 @@ fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> (Token
             .collect::<TokenStream>(),
         );
 
-        self.stack.push(mem::replace(
-            &mut self.frame,
-            TokenCursorFrame::new(
-                None,
-                if attr_style == AttrStyle::Inner {
-                    [
-                        TokenTree::token_alone(token::Pound, span),
-                        TokenTree::token_alone(token::Not, span),
-                        body,
-                    ]
-                    .into_iter()
-                    .collect::<TokenStream>()
-                } else {
-                    [TokenTree::token_alone(token::Pound, span), body]
-                        .into_iter()
-                        .collect::<TokenStream>()
-                },
-            ),
-        ));
-
-        self.next(/* desugar_doc_comments */ false)
+        if attr_style == AttrStyle::Inner {
+            vec![
+                TokenTree::token_alone(token::Pound, span),
+                TokenTree::token_alone(token::Not, span),
+                body,
+            ]
+        } else {
+            vec![TokenTree::token_alone(token::Pound, span), body]
+        }
     }
 }
 
@@ -475,7 +468,7 @@ pub fn new(
             restrictions: Restrictions::empty(),
             expected_tokens: Vec::new(),
             token_cursor: TokenCursor {
-                frame: TokenCursorFrame::new(None, tokens),
+                tree_cursor: tokens.into_trees(),
                 stack: Vec::new(),
                 num_next_calls: 0,
                 desugar_doc_comments,
@@ -739,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,
             })
     }
@@ -1142,14 +1136,16 @@ pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R
             return looker(&self.token);
         }
 
-        let frame = &self.token_cursor.frame;
-        if let Some((delim, span)) = frame.delim_sp && delim != Delimiter::Invisible {
+        let tree_cursor = &self.token_cursor.tree_cursor;
+        if let Some(&(_, delim, span)) = self.token_cursor.stack.last()
+            && delim != Delimiter::Invisible
+        {
             let all_normal = (0..dist).all(|i| {
-                let token = frame.tree_cursor.look_ahead(i);
+                let token = tree_cursor.look_ahead(i);
                 !matches!(token, Some(TokenTree::Delimited(_, Delimiter::Invisible, _)))
             });
             if all_normal {
-                return match frame.tree_cursor.look_ahead(dist - 1) {
+                return match tree_cursor.look_ahead(dist - 1) {
                     Some(tree) => match tree {
                         TokenTree::Token(token, _) => looker(token),
                         TokenTree::Delimited(dspan, delim, _) => {
@@ -1203,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())
@@ -1310,10 +1316,10 @@ fn parse_or_use_outer_attributes(
     pub(crate) fn parse_token_tree(&mut self) -> TokenTree {
         match self.token.kind {
             token::OpenDelim(..) => {
-                // Grab the tokens from this frame.
-                let frame = &self.token_cursor.frame;
-                let stream = frame.tree_cursor.stream.clone();
-                let (delim, span) = frame.delim_sp.unwrap();
+                // Grab the tokens within the delimiters.
+                let tree_cursor = &self.token_cursor.tree_cursor;
+                let stream = tree_cursor.stream.clone();
+                let (_, delim, span) = *self.token_cursor.stack.last().unwrap();
 
                 // Advance the token cursor through the entire delimited
                 // sequence. After getting the `OpenDelim` we are *within* the
index 239ed79ce2ffb825682f1fd3db0d26661cd8cf5e..7a4d53ed8bbe04d87983124b01a2586ee00ba8cb 100644 (file)
@@ -2,9 +2,11 @@
 use rustc_ast::token::{self, Delimiter, NonterminalKind, Token};
 use rustc_ast::HasTokens;
 use rustc_ast_pretty::pprust;
+use rustc_errors::IntoDiagnostic;
 use rustc_errors::PResult;
 use rustc_span::symbol::{kw, Ident};
 
+use crate::errors::UnexpectedNonterminal;
 use crate::parser::pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
 use crate::parser::{FollowedByType, ForceCollect, NtOrTt, Parser, PathStyle};
 
@@ -113,7 +115,8 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, NtOrTt
             NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
                 Some(item) => token::NtItem(item),
                 None => {
-                    return Err(self.struct_span_err(self.token.span, "expected an item keyword"));
+                    return Err(UnexpectedNonterminal::Item(self.token.span)
+                               .into_diagnostic(&self.sess.span_diagnostic));
                 }
             },
             NonterminalKind::Block => {
@@ -124,7 +127,8 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, NtOrTt
             NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? {
                 Some(s) => token::NtStmt(P(s)),
                 None => {
-                    return Err(self.struct_span_err(self.token.span, "expected a statement"));
+                    return Err(UnexpectedNonterminal::Statement(self.token.span)
+                               .into_diagnostic(&self.sess.span_diagnostic));
                 }
             },
             NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
@@ -160,9 +164,10 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, NtOrTt
                 token::NtIdent(ident, is_raw)
             }
             NonterminalKind::Ident => {
-                let token_str = pprust::token_to_string(&self.token);
-                let msg = &format!("expected ident, found {}", &token_str);
-                return Err(self.struct_span_err(self.token.span, msg));
+                return Err(UnexpectedNonterminal::Ident {
+                    span: self.token.span,
+                    token: self.token.clone(),
+                }.into_diagnostic(&self.sess.span_diagnostic));
             }
             NonterminalKind::Path => token::NtPath(
                 P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?),
@@ -175,9 +180,10 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, NtOrTt
                 if self.check_lifetime() {
                     token::NtLifetime(self.expect_lifetime().ident)
                 } else {
-                    let token_str = pprust::token_to_string(&self.token);
-                    let msg = &format!("expected a lifetime, found `{}`", &token_str);
-                    return Err(self.struct_span_err(self.token.span, msg));
+                    return Err(UnexpectedNonterminal::Lifetime {
+                        span: self.token.span,
+                        token: self.token.clone(),
+                    }.into_diagnostic(&self.sess.span_diagnostic));
                 }
             }
         };
index 912f7cc14f6cc238589469007013becf9d6239c2..b054dc59a0c9d93b43d1b2a365a4ec12d23c22ea 100644 (file)
@@ -1,6 +1,12 @@
 use super::{ForceCollect, Parser, PathStyle, TrailingToken};
 use crate::errors::{
-    InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, RemoveLet,
+    AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
+    DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
+    ExpectedCommaAfterPatternField, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow,
+    InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect,
+    RemoveLet, RepeatedMutInPattern, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
+    TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam,
+    UnexpectedVertVertInPattern,
 };
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
     PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
 };
 use rustc_ast_pretty::pprust;
-use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
+use rustc_errors::{
+    fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult,
+};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::{respan, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident};
 
-pub(super) type Expected = Option<&'static str>;
+#[derive(PartialEq, Copy, Clone)]
+pub enum Expected {
+    ParameterName,
+    ArgumentName,
+    Identifier,
+    BindingPattern,
+}
 
-/// `Expected` for function and lambda parameter patterns.
-pub(super) const PARAM_EXPECTED: Expected = Some("parameter name");
+impl Expected {
+    // FIXME(#100717): migrate users of this to proper localization
+    fn to_string_or_fallback(expected: Option<Expected>) -> &'static str {
+        match expected {
+            Some(Expected::ParameterName) => "parameter name",
+            Some(Expected::ArgumentName) => "argument name",
+            Some(Expected::Identifier) => "identifier",
+            Some(Expected::BindingPattern) => "binding pattern",
+            None => "pattern",
+        }
+    }
+}
 
 const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here";
 
@@ -56,13 +80,19 @@ enum EatOrResult {
     None,
 }
 
+/// The syntax location of a given pattern. Used for diagnostics.
+pub(super) enum PatternLocation {
+    LetBinding,
+    FunctionParameter,
+}
+
 impl<'a> Parser<'a> {
     /// Parses a pattern.
     ///
     /// Corresponds to `pat<no_top_alt>` in RFC 2535 and does not admit or-patterns
     /// at the top level. Used when parsing the parameters of lambda expressions,
     /// functions, function pointers, and `pat` macro fragments.
-    pub fn parse_pat_no_top_alt(&mut self, expected: Expected) -> PResult<'a, P<Pat>> {
+    pub fn parse_pat_no_top_alt(&mut self, expected: Option<Expected>) -> PResult<'a, P<Pat>> {
         self.parse_pat_with_range_pat(true, expected)
     }
 
@@ -76,7 +106,7 @@ pub fn parse_pat_no_top_alt(&mut self, expected: Expected) -> PResult<'a, P<Pat>
     /// simplify the grammar somewhat.
     pub fn parse_pat_allow_top_alt(
         &mut self,
-        expected: Expected,
+        expected: Option<Expected>,
         rc: RecoverComma,
         ra: RecoverColon,
         rt: CommaRecoveryMode,
@@ -88,7 +118,7 @@ pub fn parse_pat_allow_top_alt(
     /// recovered).
     fn parse_pat_allow_top_alt_inner(
         &mut self,
-        expected: Expected,
+        expected: Option<Expected>,
         rc: RecoverComma,
         ra: RecoverColon,
         rt: CommaRecoveryMode,
@@ -118,8 +148,7 @@ fn parse_pat_allow_top_alt_inner(
 
             // Check if the user wrote `foo:bar` instead of `foo::bar`.
             if ra == RecoverColon::Yes {
-                first_pat =
-                    self.maybe_recover_colon_colon_in_pat_typo_or_anon_enum(first_pat, expected);
+                first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected);
             }
 
             if let Some(leading_vert_span) = leading_vert_span {
@@ -168,9 +197,9 @@ fn parse_pat_allow_top_alt_inner(
     /// otherwise).
     pub(super) fn parse_pat_before_ty(
         &mut self,
-        expected: Expected,
+        expected: Option<Expected>,
         rc: RecoverComma,
-        syntax_loc: &str,
+        syntax_loc: PatternLocation,
     ) -> PResult<'a, (P<Pat>, bool)> {
         // We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level
         // or-patterns so that we can detect when a user tries to use it. This allows us to print a
@@ -184,27 +213,41 @@ pub(super) fn parse_pat_before_ty(
         let colon = self.eat(&token::Colon);
 
         if let PatKind::Or(pats) = &pat.kind {
-            let msg = format!("top-level or-patterns are not allowed in {}", syntax_loc);
-            let (help, fix) = if pats.len() == 1 {
-                // If all we have is a leading vert, then print a special message. This is the case
-                // if `parse_pat_allow_top_alt` returns an or-pattern with one variant.
-                let msg = "remove the `|`";
-                let fix = pprust::pat_to_string(&pat);
-                (msg, fix)
-            } else {
-                let msg = "wrap the pattern in parentheses";
-                let fix = format!("({})", pprust::pat_to_string(&pat));
-                (msg, fix)
-            };
+            let span = pat.span;
 
             if trailing_vert {
                 // We already emitted an error and suggestion to remove the trailing vert. Don't
                 // emit again.
-                self.sess.span_diagnostic.delay_span_bug(pat.span, &msg);
+
+                // FIXME(#100717): pass `TopLevelOrPatternNotAllowed::* { sub: None }` to
+                // `delay_span_bug()` instead of fluent message
+                self.sess.span_diagnostic.delay_span_bug(
+                    span,
+                    match syntax_loc {
+                        PatternLocation::LetBinding => {
+                            fluent::parse_or_pattern_not_allowed_in_let_binding
+                        }
+                        PatternLocation::FunctionParameter => {
+                            fluent::parse_or_pattern_not_allowed_in_fn_parameters
+                        }
+                    },
+                );
             } else {
-                self.struct_span_err(pat.span, &msg)
-                    .span_suggestion(pat.span, help, fix, Applicability::MachineApplicable)
-                    .emit();
+                let pat = pprust::pat_to_string(&pat);
+                let sub = if pats.len() == 1 {
+                    Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span, pat })
+                } else {
+                    Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat })
+                };
+
+                self.sess.emit_err(match syntax_loc {
+                    PatternLocation::LetBinding => {
+                        TopLevelOrPatternNotAllowed::LetBinding { span, sub }
+                    }
+                    PatternLocation::FunctionParameter => {
+                        TopLevelOrPatternNotAllowed::FunctionParameter { span, sub }
+                    }
+                });
             }
         }
 
@@ -221,15 +264,15 @@ pub(super) fn parse_fn_param_pat_colon(&mut self) -> PResult<'a, (P<Pat>, bool)>
         // a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that
         // separately.
         if let token::OrOr = self.token.kind {
-            let span = self.token.span;
-            let mut err = self.struct_span_err(span, "unexpected `||` before function parameter");
-            err.span_suggestion(span, "remove the `||`", "", Applicability::MachineApplicable);
-            err.note("alternatives in or-patterns are separated with `|`, not `||`");
-            err.emit();
+            self.sess.emit_err(UnexpectedVertVertBeforeFunctionParam { span: self.token.span });
             self.bump();
         }
 
-        self.parse_pat_before_ty(PARAM_EXPECTED, RecoverComma::No, "function parameters")
+        self.parse_pat_before_ty(
+            Some(Expected::ParameterName),
+            RecoverComma::No,
+            PatternLocation::FunctionParameter,
+        )
     }
 
     /// Eat the or-pattern `|` separator.
@@ -239,7 +282,7 @@ fn eat_or_separator(&mut self, lo: Option<Span>) -> EatOrResult {
             EatOrResult::TrailingVert
         } else if matches!(self.token.kind, token::OrOr) {
             // Found `||`; Recover and pretend we parsed `|`.
-            self.ban_unexpected_or_or(lo);
+            self.sess.emit_err(UnexpectedVertVertInPattern { span: self.token.span, start: lo });
             self.bump();
             EatOrResult::AteOr
         } else if self.eat(&token::BinOp(token::Or)) {
@@ -273,7 +316,13 @@ fn recover_trailing_vert(&mut self, lo: Option<Span>) -> bool {
         });
         match (is_end_ahead, &self.token.kind) {
             (true, token::BinOp(token::Or) | token::OrOr) => {
-                self.ban_illegal_vert(lo, "trailing", "not allowed in an or-pattern");
+                // A `|` or possibly `||` token shouldn't be here. Ban it.
+                self.sess.emit_err(TrailingVertNotAllowed {
+                    span: self.token.span,
+                    start: lo,
+                    token: self.token.clone(),
+                    note_double_vert: matches!(self.token.kind, token::OrOr).then_some(()),
+                });
                 self.bump();
                 true
             }
@@ -281,46 +330,12 @@ fn recover_trailing_vert(&mut self, lo: Option<Span>) -> bool {
         }
     }
 
-    /// We have parsed `||` instead of `|`. Error and suggest `|` instead.
-    fn ban_unexpected_or_or(&mut self, lo: Option<Span>) {
-        let mut err = self.struct_span_err(self.token.span, "unexpected token `||` in pattern");
-        err.span_suggestion(
-            self.token.span,
-            "use a single `|` to separate multiple alternative patterns",
-            "|",
-            Applicability::MachineApplicable,
-        );
-        if let Some(lo) = lo {
-            err.span_label(lo, WHILE_PARSING_OR_MSG);
-        }
-        err.emit();
-    }
-
-    /// A `|` or possibly `||` token shouldn't be here. Ban it.
-    fn ban_illegal_vert(&mut self, lo: Option<Span>, pos: &str, ctx: &str) {
-        let span = self.token.span;
-        let mut err = self.struct_span_err(span, &format!("a {} `|` is {}", pos, ctx));
-        err.span_suggestion(
-            span,
-            &format!("remove the `{}`", pprust::token_to_string(&self.token)),
-            "",
-            Applicability::MachineApplicable,
-        );
-        if let Some(lo) = lo {
-            err.span_label(lo, WHILE_PARSING_OR_MSG);
-        }
-        if let token::OrOr = self.token.kind {
-            err.note("alternatives in or-patterns are separated with `|`, not `||`");
-        }
-        err.emit();
-    }
-
     /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
     /// allowed).
     fn parse_pat_with_range_pat(
         &mut self,
         allow_range_pat: bool,
-        expected: Expected,
+        expected: Option<Expected>,
     ) -> PResult<'a, P<Pat>> {
         maybe_recover_from_interpolated_ty_qpath!(self, true);
         maybe_whole!(self, NtPat, |x| x);
@@ -416,7 +431,7 @@ fn parse_pat_with_range_pat(
             let lt = self.expect_lifetime();
             let (lit, _) =
                 self.recover_unclosed_char(lt.ident, Parser::mk_token_lit_char, |self_| {
-                    let expected = expected.unwrap_or("pattern");
+                    let expected = Expected::to_string_or_fallback(expected);
                     let msg = format!(
                         "expected {}, found {}",
                         expected,
@@ -457,15 +472,7 @@ fn recover_dotdotdot_rest_pat(&mut self, lo: Span) -> PatKind {
         self.bump(); // `...`
 
         // The user probably mistook `...` for a rest pattern `..`.
-        self.struct_span_err(lo, "unexpected `...`")
-            .span_label(lo, "not a valid pattern")
-            .span_suggestion_short(
-                lo,
-                "for a rest pattern, use `..` instead of `...`",
-                "..",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        self.sess.emit_err(DotDotDotRestPattern { span: lo });
         PatKind::Rest
     }
 
@@ -490,7 +497,7 @@ fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> {
         // At this point we attempt to parse `@ $pat_rhs` and emit an error.
         self.bump(); // `@`
         let mut rhs = self.parse_pat_no_top_alt(None)?;
-        let sp = lhs.span.to(rhs.span);
+        let whole_span = lhs.span.to(rhs.span);
 
         if let PatKind::Ident(_, _, sub @ None) = &mut rhs.kind {
             // The user inverted the order, so help them fix that.
@@ -499,27 +506,23 @@ fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> {
             // The RHS is now the full pattern.
             *sub = Some(lhs);
 
-            self.struct_span_err(sp, "pattern on wrong side of `@`")
-                .span_label(lhs_span, "pattern on the left, should be on the right")
-                .span_label(rhs.span, "binding on the right, should be on the left")
-                .span_suggestion(
-                    sp,
-                    "switch the order",
-                    pprust::pat_to_string(&rhs),
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+            self.sess.emit_err(PatternOnWrongSideOfAt {
+                whole_span,
+                whole_pat: pprust::pat_to_string(&rhs),
+                pattern: lhs_span,
+                binding: rhs.span,
+            });
         } else {
             // The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`.
             rhs.kind = PatKind::Wild;
-            self.struct_span_err(sp, "left-hand side of `@` must be a binding")
-                .span_label(lhs.span, "interpreted as a pattern, not a binding")
-                .span_label(rhs.span, "also a pattern")
-                .note("bindings are `x`, `mut x`, `ref x`, and `ref mut x`")
-                .emit();
+            self.sess.emit_err(ExpectedBindingLeftOfAt {
+                whole_span,
+                lhs: lhs.span,
+                rhs: rhs.span,
+            });
         }
 
-        rhs.span = sp;
+        rhs.span = whole_span;
         Ok(rhs)
     }
 
@@ -534,35 +537,23 @@ fn ban_pat_range_if_ambiguous(&self, pat: &Pat) {
             _ => return,
         }
 
-        self.struct_span_err(pat.span, "the range pattern here has ambiguous interpretation")
-            .span_suggestion(
-                pat.span,
-                "add parentheses to clarify the precedence",
-                format!("({})", pprust::pat_to_string(&pat)),
-                // "ambiguous interpretation" implies that we have to be guessing
-                Applicability::MaybeIncorrect,
-            )
-            .emit();
+        self.sess
+            .emit_err(AmbiguousRangePattern { span: pat.span, pat: pprust::pat_to_string(&pat) });
     }
 
     /// Parse `&pat` / `&mut pat`.
-    fn parse_pat_deref(&mut self, expected: Expected) -> PResult<'a, PatKind> {
+    fn parse_pat_deref(&mut self, expected: Option<Expected>) -> PResult<'a, PatKind> {
         self.expect_and()?;
-        self.recover_lifetime_in_deref_pat();
-        let mutbl = self.parse_mutability();
-        let subpat = self.parse_pat_with_range_pat(false, expected)?;
-        Ok(PatKind::Ref(subpat, mutbl))
-    }
-
-    fn recover_lifetime_in_deref_pat(&mut self) {
         if let token::Lifetime(name) = self.token.kind {
             self.bump(); // `'a`
 
-            let span = self.prev_token.span;
-            self.struct_span_err(span, &format!("unexpected lifetime `{}` in pattern", name))
-                .span_suggestion(span, "remove the lifetime", "", Applicability::MachineApplicable)
-                .emit();
+            self.sess
+                .emit_err(UnexpectedLifetimeInPattern { span: self.prev_token.span, symbol: name });
         }
+
+        let mutbl = self.parse_mutability();
+        let subpat = self.parse_pat_with_range_pat(false, expected)?;
+        Ok(PatKind::Ref(subpat, mutbl))
     }
 
     /// Parse a tuple or parenthesis pattern.
@@ -590,7 +581,8 @@ fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> {
         let mut_span = self.prev_token.span;
 
         if self.eat_keyword(kw::Ref) {
-            return self.recover_mut_ref_ident(mut_span);
+            self.sess.emit_err(RefMutOrderIncorrect { span: mut_span.to(self.prev_token.span) });
+            return self.parse_pat_ident(BindingAnnotation::REF_MUT);
         }
 
         self.recover_additional_muts();
@@ -603,7 +595,7 @@ fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> {
         }
 
         // Parse the pattern we hope to be an identifier.
-        let mut pat = self.parse_pat_no_top_alt(Some("identifier"))?;
+        let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier))?;
 
         // If we don't have `mut $ident (@ pat)?`, error.
         if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind
@@ -620,22 +612,6 @@ fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> {
         Ok(pat.into_inner().kind)
     }
 
-    /// Recover on `mut ref? ident @ pat` and suggest
-    /// that the order of `mut` and `ref` is incorrect.
-    fn recover_mut_ref_ident(&mut self, lo: Span) -> PResult<'a, PatKind> {
-        let mutref_span = lo.to(self.prev_token.span);
-        self.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect")
-            .span_suggestion(
-                mutref_span,
-                "try switching the order",
-                "ref mut",
-                Applicability::MachineApplicable,
-            )
-            .emit();
-
-        self.parse_pat_ident(BindingAnnotation::REF_MUT)
-    }
-
     /// Turn all by-value immutable bindings in a pattern into mutable bindings.
     /// Returns `true` if any change was made.
     fn make_all_value_bindings_mutable(pat: &mut P<Pat>) -> bool {
@@ -660,16 +636,13 @@ fn visit_pat(&mut self, pat: &mut P<Pat>) {
     /// Error on `mut $pat` where `$pat` is not an ident.
     fn ban_mut_general_pat(&self, lo: Span, pat: &Pat, changed_any_binding: bool) {
         let span = lo.to(pat.span);
-        let fix = pprust::pat_to_string(&pat);
-        let (problem, suggestion) = if changed_any_binding {
-            ("`mut` must be attached to each individual binding", "add `mut` to each binding")
+        let pat = pprust::pat_to_string(&pat);
+
+        self.sess.emit_err(if changed_any_binding {
+            InvalidMutInPattern::NestedIdent { span, pat }
         } else {
-            ("`mut` must be followed by a named binding", "remove the `mut` prefix")
-        };
-        self.struct_span_err(span, problem)
-            .span_suggestion(span, suggestion, fix, Applicability::MachineApplicable)
-            .note("`mut` may be followed by `variable` and `variable @ pattern`")
-            .emit();
+            InvalidMutInPattern::NonIdent { span, pat }
+        });
     }
 
     /// Eat any extraneous `mut`s and error + recover if we ate any.
@@ -680,15 +653,7 @@ fn recover_additional_muts(&mut self) {
             return;
         }
 
-        let span = lo.to(self.prev_token.span);
-        self.struct_span_err(span, "`mut` on a binding may not be repeated")
-            .span_suggestion(
-                span,
-                "remove the additional `mut`s",
-                "",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        self.sess.emit_err(RepeatedMutInPattern { span: lo.to(self.prev_token.span) });
     }
 
     /// Parse macro invocation
@@ -702,11 +667,11 @@ fn parse_pat_mac_invoc(&mut self, path: Path) -> PResult<'a, PatKind> {
     fn fatal_unexpected_non_pat(
         &mut self,
         err: DiagnosticBuilder<'a, ErrorGuaranteed>,
-        expected: Expected,
+        expected: Option<Expected>,
     ) -> PResult<'a, P<Pat>> {
         err.cancel();
 
-        let expected = expected.unwrap_or("pattern");
+        let expected = Expected::to_string_or_fallback(expected);
         let msg = format!("expected {}, found {}", expected, super::token_descr(&self.token));
 
         let mut err = self.struct_span_err(self.token.span, &msg);
@@ -774,28 +739,18 @@ pub(super) fn inclusive_range_with_incorrect_end(&mut self) {
                     let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
                 }
 
-                self.error_inclusive_range_with_extra_equals(span_with_eq);
+                self.sess.emit_err(InclusiveRangeExtraEquals { span: span_with_eq });
             }
             token::Gt if no_space => {
-                self.error_inclusive_range_match_arrow(span);
+                let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi();
+                self.sess.emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat });
+            }
+            _ => {
+                self.sess.emit_err(InclusiveRangeNoEnd { span });
             }
-            _ => self.error_inclusive_range_with_no_end(span),
         }
     }
 
-    fn error_inclusive_range_with_extra_equals(&self, span: Span) {
-        self.sess.emit_err(InclusiveRangeExtraEquals { span });
-    }
-
-    fn error_inclusive_range_match_arrow(&self, span: Span) {
-        let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi();
-        self.sess.emit_err(InclusiveRangeMatchArrow { span, after_pat });
-    }
-
-    fn error_inclusive_range_with_no_end(&self, span: Span) {
-        self.sess.emit_err(InclusiveRangeNoEnd { span });
-    }
-
     /// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.
     ///
     /// The form `...X` is prohibited to reduce confusion with the potential
@@ -804,14 +759,7 @@ fn parse_pat_range_to(&mut self, mut re: Spanned<RangeEnd>) -> PResult<'a, PatKi
         let end = self.parse_pat_range_end()?;
         if let RangeEnd::Included(syn @ RangeSyntax::DotDotDot) = &mut re.node {
             *syn = RangeSyntax::DotDotEq;
-            self.struct_span_err(re.span, "range-to patterns with `...` are not allowed")
-                .span_suggestion_short(
-                    re.span,
-                    "use `..=` instead",
-                    "..=",
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+            self.sess.emit_err(DotDotDotRangeToPatternNotAllowed { span: re.span });
         }
         Ok(PatKind::Range(None, Some(end), re))
     }
@@ -876,7 +824,7 @@ fn can_be_ident_pat(&mut self) -> bool {
     fn parse_pat_ident(&mut self, binding_annotation: BindingAnnotation) -> PResult<'a, PatKind> {
         let ident = self.parse_ident()?;
         let sub = if self.eat(&token::At) {
-            Some(self.parse_pat_no_top_alt(Some("binding pattern"))?)
+            Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern))?)
         } else {
             None
         };
@@ -887,8 +835,8 @@ fn parse_pat_ident(&mut self, binding_annotation: BindingAnnotation) -> PResult<
         // binding mode then we do not end up here, because the lookahead
         // will direct us over to `parse_enum_variant()`.
         if self.token == token::OpenDelim(Delimiter::Parenthesis) {
-            return Err(self
-                .struct_span_err(self.prev_token.span, "expected identifier, found enum pattern"));
+            return Err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span }
+                .into_diagnostic(&self.sess.span_diagnostic));
         }
 
         Ok(PatKind::Ident(binding_annotation, ident, sub))
@@ -970,7 +918,7 @@ fn parse_pat_box(&mut self) -> PResult<'a, PatKind> {
             // We cannot use `parse_pat_ident()` since it will complain `box`
             // is not an identifier.
             let sub = if self.eat(&token::At) {
-                Some(self.parse_pat_no_top_alt(Some("binding pattern"))?)
+                Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern))?)
             } else {
                 None
             };
@@ -1005,7 +953,8 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<PatField>, bool)> {
 
             // check that a comma comes after every field
             if !ate_comma {
-                let err = self.struct_span_err(self.token.span, "expected `,`");
+                let err = ExpectedCommaAfterPatternField { span: self.token.span }
+                    .into_diagnostic(&self.sess.span_diagnostic);
                 if let Some(mut delayed) = delayed_err {
                     delayed.emit();
                 }
@@ -1013,12 +962,15 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<PatField>, bool)> {
             }
             ate_comma = false;
 
-            if self.check(&token::DotDot) || self.token == token::DotDotDot {
+            if self.check(&token::DotDot)
+                || self.check_noexpect(&token::DotDotDot)
+                || self.check_keyword(kw::Underscore)
+            {
                 etc = true;
                 let mut etc_sp = self.token.span;
 
-                self.recover_one_fewer_dotdot();
-                self.bump(); // `..` || `...`
+                self.recover_bad_dot_dot();
+                self.bump(); // `..` || `...` || `_`
 
                 if self.token == token::CloseDelim(Delimiter::Brace) {
                     etc_span = Some(etc_sp);
@@ -1111,21 +1063,15 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<PatField>, bool)> {
         Ok((fields, etc))
     }
 
-    /// Recover on `...` as if it were `..` to avoid further errors.
+    /// Recover on `...` or `_` as if it were `..` to avoid further errors.
     /// See issue #46718.
-    fn recover_one_fewer_dotdot(&self) {
-        if self.token != token::DotDotDot {
+    fn recover_bad_dot_dot(&self) {
+        if self.token == token::DotDot {
             return;
         }
 
-        self.struct_span_err(self.token.span, "expected field pattern, found `...`")
-            .span_suggestion(
-                self.token.span,
-                "to omit remaining fields, use one fewer `.`",
-                "..",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        let token_str = pprust::token_to_string(&self.token);
+        self.sess.emit_err(DotDotDotForRemainingFields { span: self.token.span, token_str });
     }
 
     fn parse_pat_field(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, PatField> {
index 58c7a398f14252e3e2ac7cd4bcf79c16b9049ab6..3afda5f69f0e1f4eceb99a29858507af08b1071c 100644 (file)
@@ -1,18 +1,13 @@
 use super::attr::InnerAttrForbiddenReason;
 use super::diagnostics::AttemptLocalParseRecovery;
 use super::expr::LhsExpr;
-use super::pat::RecoverComma;
+use super::pat::{PatternLocation, RecoverComma};
 use super::path::PathStyle;
 use super::TrailingToken;
 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,12 +269,13 @@ 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();
         }
 
         self.report_invalid_identifier_error()?;
-        let (pat, colon) = self.parse_pat_before_ty(None, RecoverComma::Yes, "`let` bindings")?;
+        let (pat, colon) =
+            self.parse_pat_before_ty(None, RecoverComma::Yes, PatternLocation::LetBinding)?;
 
         let (err, ty) = if colon {
             // Save the state of the parser before parsing type normally, in case there is a `:`
@@ -372,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(())
     }
@@ -380,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(),
                     },
@@ -394,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(),
                 },
@@ -409,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 8b4f0ab8feb848a0008a9a212aae65bbc0f332ec..a19ea04fa5e75e47128fa769952be3b6083a68c6 100644 (file)
@@ -1,6 +1,12 @@
 use super::{Parser, PathStyle, TokenType};
 
-use crate::errors::{ExpectedFnPathFoundFnKeyword, FnPtrWithGenerics, FnPtrWithGenericsSugg};
+use crate::errors::{
+    DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
+    FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
+    InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
+    NegativeBoundsNotSupported, NegativeBoundsNotSupportedSugg, NestedCVariadicType,
+    ReturnTypesUseThinArrow,
+};
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 
 use ast::DUMMY_NODE_ID;
@@ -11,8 +17,7 @@
     self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
     MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
 };
-use rustc_ast_pretty::pprust;
-use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
+use rustc_errors::{Applicability, PResult};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Symbol;
@@ -44,24 +49,17 @@ pub(super) enum AllowPlus {
     No,
 }
 
-#[derive(PartialEq, Clone, Copy)]
+#[derive(PartialEq)]
 pub(super) enum RecoverQPath {
     Yes,
     No,
 }
 
-#[derive(PartialEq, Clone, Copy)]
 pub(super) enum RecoverQuestionMark {
     Yes,
     No,
 }
 
-#[derive(PartialEq, Clone, Copy)]
-pub(super) enum RecoverAnonEnum {
-    Yes,
-    No,
-}
-
 /// Signals whether parsing a type should recover `->`.
 ///
 /// More specifically, when parsing a function like:
@@ -94,7 +92,7 @@ fn can_recover(self, token: &TokenKind) -> bool {
 }
 
 // Is `...` (`CVarArgs`) legal at this level of type parsing?
-#[derive(PartialEq, Clone, Copy)]
+#[derive(PartialEq)]
 enum AllowCVariadic {
     Yes,
     No,
@@ -119,7 +117,6 @@ pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::Yes,
-            RecoverAnonEnum::No,
         )
     }
 
@@ -134,7 +131,6 @@ pub(super) fn parse_ty_with_generics_recovery(
             RecoverReturnSign::Yes,
             Some(ty_params),
             RecoverQuestionMark::Yes,
-            RecoverAnonEnum::No,
         )
     }
 
@@ -149,7 +145,6 @@ pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::Yes,
-            RecoverAnonEnum::Yes,
         )
     }
 
@@ -167,7 +162,6 @@ pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::Yes,
-            RecoverAnonEnum::No,
         )
     }
 
@@ -181,7 +175,6 @@ pub(super) fn parse_as_cast_ty(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::No,
-            RecoverAnonEnum::No,
         )
     }
 
@@ -193,7 +186,6 @@ pub(super) fn parse_no_question_mark_recover(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::No,
-            RecoverAnonEnum::No,
         )
     }
 
@@ -206,7 +198,6 @@ pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::OnlyFatArrow,
             None,
             RecoverQuestionMark::Yes,
-            RecoverAnonEnum::No,
         )
     }
 
@@ -226,21 +217,13 @@ pub(super) fn parse_ret_ty(
                 recover_return_sign,
                 None,
                 RecoverQuestionMark::Yes,
-                RecoverAnonEnum::Yes,
             )?;
             FnRetTy::Ty(ty)
         } else if recover_return_sign.can_recover(&self.token.kind) {
             // Don't `eat` to prevent `=>` from being added as an expected token which isn't
             // actually expected and could only confuse users
             self.bump();
-            self.struct_span_err(self.prev_token.span, "return types are denoted using `->`")
-                .span_suggestion_short(
-                    self.prev_token.span,
-                    "use `->` instead",
-                    "->",
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+            self.sess.emit_err(ReturnTypesUseThinArrow { span: self.prev_token.span });
             let ty = self.parse_ty_common(
                 allow_plus,
                 AllowCVariadic::No,
@@ -248,7 +231,6 @@ pub(super) fn parse_ret_ty(
                 recover_return_sign,
                 None,
                 RecoverQuestionMark::Yes,
-                RecoverAnonEnum::Yes,
             )?;
             FnRetTy::Ty(ty)
         } else {
@@ -264,7 +246,6 @@ fn parse_ty_common(
         recover_return_sign: RecoverReturnSign,
         ty_generics: Option<&Generics>,
         recover_question_mark: RecoverQuestionMark,
-        recover_anon_enum: RecoverAnonEnum,
     ) -> PResult<'a, P<Ty>> {
         let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
         maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
@@ -328,7 +309,7 @@ fn parse_ty_common(
                 AllowCVariadic::No => {
                     // FIXME(Centril): Should we just allow `...` syntactically
                     // anywhere in a type and use semantic restrictions instead?
-                    self.error_illegal_c_varadic_ty(lo);
+                    self.sess.emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) });
                     TyKind::Err
                 }
             }
@@ -348,50 +329,9 @@ fn parse_ty_common(
             AllowPlus::Yes => self.maybe_recover_from_bad_type_plus(&ty)?,
             AllowPlus::No => self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty),
         }
-        if RecoverQuestionMark::Yes == recover_question_mark {
+        if let RecoverQuestionMark::Yes = recover_question_mark {
             ty = self.maybe_recover_from_question_mark(ty);
         }
-        if recover_anon_enum == RecoverAnonEnum::Yes
-            && self.check_noexpect(&token::BinOp(token::Or))
-            && self.look_ahead(1, |t| t.can_begin_type())
-        {
-            let mut pipes = vec![self.token.span];
-            let mut types = vec![ty];
-            loop {
-                if !self.eat(&token::BinOp(token::Or)) {
-                    break;
-                }
-                pipes.push(self.prev_token.span);
-                types.push(self.parse_ty_common(
-                    allow_plus,
-                    allow_c_variadic,
-                    recover_qpath,
-                    recover_return_sign,
-                    ty_generics,
-                    recover_question_mark,
-                    RecoverAnonEnum::No,
-                )?);
-            }
-            let mut err = self.struct_span_err(pipes, "anonymous enums are not supported");
-            for ty in &types {
-                err.span_label(ty.span, "");
-            }
-            err.help(&format!(
-                "create a named `enum` and use it here instead:\nenum Name {{\n{}\n}}",
-                types
-                    .iter()
-                    .enumerate()
-                    .map(|(i, t)| format!(
-                        "    Variant{}({}),",
-                        i + 1, // Lets not confuse people with zero-indexing :)
-                        pprust::to_string(|s| s.print_type(&t)),
-                    ))
-                    .collect::<Vec<_>>()
-                    .join("\n"),
-            ));
-            err.emit();
-            return Ok(self.mk_ty(lo.to(self.prev_token.span), TyKind::Err));
-        }
         if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
     }
 
@@ -431,8 +371,7 @@ fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResul
         let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus());
         let bounds = self.parse_generic_bounds_common(allow_plus, None)?;
         if lt_no_plus {
-            self.struct_span_err(lo, "lifetime in trait object type must be followed by `+`")
-                .emit();
+            self.sess.emit_err(NeedPlusAfterTraitObjectLifetime { span: lo });
         }
         Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
     }
@@ -466,14 +405,10 @@ fn parse_remaining_bounds(
     fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> {
         let mutbl = self.parse_const_or_mut().unwrap_or_else(|| {
             let span = self.prev_token.span;
-            self.struct_span_err(span, "expected `mut` or `const` keyword in raw pointer type")
-                .span_suggestions(
-                    span.shrink_to_hi(),
-                    "add `mut` or `const` here",
-                    ["mut ".to_string(), "const ".to_string()],
-                    Applicability::HasPlaceholders,
-                )
-                .emit();
+            self.sess.emit_err(ExpectedMutOrConstInRawPointerType {
+                span,
+                after_asterisk: span.shrink_to_hi(),
+            });
             Mutability::Not
         });
         let ty = self.parse_ty_no_plus()?;
@@ -528,16 +463,13 @@ fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
                 let lifetime_span = self.token.span;
                 let span = and_span.to(lifetime_span);
 
-                let mut err = self.struct_span_err(span, "lifetime must precede `mut`");
-                if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) {
-                    err.span_suggestion(
-                        span,
-                        "place the lifetime before `mut`",
-                        format!("&{} mut", lifetime_src),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                err.emit();
+                let (suggest_lifetime, snippet) =
+                    if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) {
+                        (Some(span), lifetime_src)
+                    } else {
+                        (None, String::new())
+                    };
+                self.sess.emit_err(LifetimeAfterMut { span, suggest_lifetime, snippet });
 
                 opt_lifetime = Some(self.expect_lifetime());
             }
@@ -547,14 +479,7 @@ fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
         {
             // We have `&dyn mut ...`, which is invalid and should be `&mut dyn ...`.
             let span = and_span.to(self.look_ahead(1, |t| t.span));
-            let mut err = self.struct_span_err(span, "`mut` must precede `dyn`");
-            err.span_suggestion(
-                span,
-                "place `mut` before `dyn`",
-                "&mut dyn",
-                Applicability::MachineApplicable,
-            );
-            err.emit();
+            self.sess.emit_err(DynAfterMut { span });
 
             // Recovery
             mutbl = Mutability::Mut;
@@ -608,10 +533,10 @@ fn parse_ty_bare_fn(
             // If we ever start to allow `const fn()`, then update
             // feature gating for `#![feature(const_extern_fn)]` to
             // cover it.
-            self.error_fn_ptr_bad_qualifier(whole_span, span, "const");
+            self.sess.emit_err(FnPointerCannotBeConst { span: whole_span, qualifier: span });
         }
         if let ast::Async::Yes { span, .. } = asyncness {
-            self.error_fn_ptr_bad_qualifier(whole_span, span, "async");
+            self.sess.emit_err(FnPointerCannotBeAsync { span: whole_span, qualifier: span });
         }
         let decl_span = span_start.to(self.token.span);
         Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl, decl_span })))
@@ -659,19 +584,6 @@ fn recover_fn_ptr_with_generics(
         Ok(())
     }
 
-    /// Emit an error for the given bad function pointer qualifier.
-    fn error_fn_ptr_bad_qualifier(&self, span: Span, qual_span: Span, qual: &str) {
-        self.struct_span_err(span, &format!("an `fn` pointer type cannot be `{}`", qual))
-            .span_label(qual_span, format!("`{}` because of this", qual))
-            .span_suggestion_short(
-                qual_span,
-                &format!("remove the `{}` qualifier", qual),
-                "",
-                Applicability::MaybeIncorrect,
-            )
-            .emit();
-    }
-
     /// Parses an `impl B0 + ... + Bn` type.
     fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
         // Always parse bounds greedily for better error recovery.
@@ -702,7 +614,7 @@ fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
     /// Is a `dyn B0 + ... + Bn` type allowed here?
     fn is_explicit_dyn_type(&mut self) -> bool {
         self.check_keyword(kw::Dyn)
-            && (!self.token.uninterpolated_span().rust_2015()
+            && (self.token.uninterpolated_span().rust_2018()
                 || self.look_ahead(1, |t| {
                     (t.can_begin_bound() || t.kind == TokenKind::BinOp(token::Star))
                         && !can_continue_type_after_non_fn_ident(t)
@@ -758,16 +670,6 @@ fn parse_path_start_ty(
         }
     }
 
-    fn error_illegal_c_varadic_ty(&self, lo: Span) {
-        struct_span_err!(
-            self.sess.span_diagnostic,
-            lo.to(self.prev_token.span),
-            E0743,
-            "C-variadic type `...` may not be nested inside another type",
-        )
-        .emit();
-    }
-
     pub(super) fn parse_generic_bounds(
         &mut self,
         colon_span: Option<Span>,
@@ -797,15 +699,7 @@ fn parse_generic_bounds_common(
         {
             if self.token.is_keyword(kw::Dyn) {
                 // Account for `&dyn Trait + dyn Other`.
-                self.struct_span_err(self.token.span, "invalid `dyn` keyword")
-                    .help("`dyn` is only needed at the start of a trait `+`-separated list")
-                    .span_suggestion(
-                        self.token.span,
-                        "remove this keyword",
-                        "",
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
+                self.sess.emit_err(InvalidDynKeyword { span: self.token.span });
                 self.bump();
             }
             match self.parse_generic_bound()? {
@@ -842,11 +736,7 @@ fn error_negative_bounds(
         bounds: &[GenericBound],
         negative_bounds: Vec<Span>,
     ) {
-        let negative_bounds_len = negative_bounds.len();
-        let last_span = *negative_bounds.last().expect("no negative bounds, but still error?");
-        let mut err = self.struct_span_err(negative_bounds, "negative bounds are not supported");
-        err.span_label(last_span, "negative bounds are not supported");
-        if let Some(bound_list) = colon_span {
+        let sub = if let Some(bound_list) = colon_span {
             let bound_list = bound_list.to(self.prev_token.span);
             let mut new_bound_list = String::new();
             if !bounds.is_empty() {
@@ -857,14 +747,18 @@ fn error_negative_bounds(
                 }
                 new_bound_list = new_bound_list.replacen(" +", ":", 1);
             }
-            err.tool_only_span_suggestion(
+
+            Some(NegativeBoundsNotSupportedSugg {
                 bound_list,
-                &format!("remove the bound{}", pluralize!(negative_bounds_len)),
-                new_bound_list,
-                Applicability::MachineApplicable,
-            );
-        }
-        err.emit();
+                num_bounds: negative_bounds.len(),
+                fixed: new_bound_list,
+            })
+        } else {
+            None
+        };
+
+        let last_span = *negative_bounds.last().expect("no negative bounds, but still error?");
+        self.sess.emit_err(NegativeBoundsNotSupported { negative_bounds, last_span, sub });
     }
 
     /// Parses a bound according to the grammar:
index a6dfcd29762474933a31022e2f09f409d3e35865..088a87ca5710457386e77017260650aa8cfb4daf 100644 (file)
@@ -273,7 +273,13 @@ fn next(&mut self) -> Option<Piece<'a>> {
                                 );
                             }
                         } else {
-                            self.suggest_positional_arg_instead_of_captured_arg(arg);
+                            if let Some(&(_, maybe)) = self.cur.peek() {
+                                if maybe == '?' {
+                                    self.suggest_format();
+                                } else {
+                                    self.suggest_positional_arg_instead_of_captured_arg(arg);
+                                }
+                            }
                         }
                         Some(NextArgument(Box::new(arg)))
                     }
@@ -832,6 +838,27 @@ fn integer(&mut self) -> Option<usize> {
         if found { Some(cur) } else { None }
     }
 
+    fn suggest_format(&mut self) {
+        if let (Some(pos), Some(_)) = (self.consume_pos('?'), self.consume_pos(':')) {
+            let word = self.word();
+            let _end = self.current_pos();
+            let pos = self.to_span_index(pos);
+            self.errors.insert(
+                0,
+                ParseError {
+                    description: "expected format parameter to occur after `:`".to_owned(),
+                    note: Some(
+                        format!("`?` comes after `:`, try `{}:{}` instead", word, "?").to_owned(),
+                    ),
+                    label: "expected `?` to occur after `:`".to_owned(),
+                    span: pos.to(pos),
+                    secondary_label: None,
+                    should_be_replaced_with_positional_argument: false,
+                },
+            );
+        }
+    }
+
     fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) {
         if let Some(end) = self.consume_pos('.') {
             let byte_pos = self.to_span_index(end);
index d67d52da497468b5d2f484aa896fd94d6ef21167..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};
@@ -174,6 +170,9 @@ fn check_attributes(
                 sym::rustc_has_incoherent_inherent_impls => {
                     self.check_has_incoherent_inherent_impls(&attr, span, target)
                 }
+                sym::ffi_pure => self.check_ffi_pure(attr.span, attrs, target),
+                sym::ffi_const => self.check_ffi_const(attr.span, target),
+                sym::ffi_returns_twice => self.check_ffi_returns_twice(attr.span, target),
                 sym::rustc_const_unstable
                 | sym::rustc_const_stable
                 | sym::unstable
@@ -396,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(' ', "_"),
                 },
@@ -465,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 });
             }
         }
     }
@@ -1213,6 +1212,38 @@ fn check_has_incoherent_inherent_impls(
         }
     }
 
+    fn check_ffi_pure(&self, attr_span: Span, attrs: &[Attribute], target: Target) -> bool {
+        if target != Target::ForeignFn {
+            self.tcx.sess.emit_err(errors::FfiPureInvalidTarget { attr_span });
+            return false;
+        }
+        if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
+            // `#[ffi_const]` functions cannot be `#[ffi_pure]`
+            self.tcx.sess.emit_err(errors::BothFfiConstAndPure { attr_span });
+            false
+        } else {
+            true
+        }
+    }
+
+    fn check_ffi_const(&self, attr_span: Span, target: Target) -> bool {
+        if target == Target::ForeignFn {
+            true
+        } else {
+            self.tcx.sess.emit_err(errors::FfiConstInvalidTarget { attr_span });
+            false
+        }
+    }
+
+    fn check_ffi_returns_twice(&self, attr_span: Span, target: Target) -> bool {
+        if target == Target::ForeignFn {
+            true
+        } else {
+            self.tcx.sess.emit_err(errors::FfiReturnsTwiceInvalidTarget { attr_span });
+            false
+        }
+    }
+
     /// Warns against some misuses of `#[must_use]`
     fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) -> bool {
         if !matches!(
@@ -1680,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,
                             });
@@ -1701,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,
                         });
@@ -1721,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;
                     }
@@ -1733,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,
                             });
@@ -1754,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;
                 }
             };
@@ -1775,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)
@@ -1930,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,
@@ -2140,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);
             }
 
@@ -2153,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,
@@ -2163,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,
@@ -2178,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,
@@ -2193,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,
@@ -2343,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 97169a6367c3d97447f9b13e383b85b856c86ccb..68b098e3457b7b77fd6c1d455aef2065cbf121a2 100644 (file)
@@ -348,6 +348,34 @@ pub struct HasIncoherentInherentImpl {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(passes_both_ffi_const_and_pure, code = "E0757")]
+pub struct BothFfiConstAndPure {
+    #[primary_span]
+    pub attr_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_ffi_pure_invalid_target, code = "E0755")]
+pub struct FfiPureInvalidTarget {
+    #[primary_span]
+    pub attr_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_ffi_const_invalid_target, code = "E0756")]
+pub struct FfiConstInvalidTarget {
+    #[primary_span]
+    pub attr_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_ffi_returns_twice_invalid_target, code = "E0724")]
+pub struct FfiReturnsTwiceInvalidTarget {
+    #[primary_span]
+    pub attr_span: Span,
+}
+
 #[derive(LintDiagnostic)]
 #[diag(passes_must_use_async)]
 pub struct MustUseAsync {
index d143adb2eb9417c50e879e693296dedf428fba94..de0e50a65de6ebba0d48d65f729b8ab01cf63f99 100644 (file)
@@ -74,37 +74,26 @@ fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, owner: hir::OwnerI
             .expect("owning item has no entry");
 
         if max != self.hir_ids_seen.len() - 1 {
-            // Collect the missing ItemLocalIds
-            let missing: Vec<_> = (0..=max as u32)
-                .filter(|&i| !self.hir_ids_seen.contains(ItemLocalId::from_u32(i)))
-                .collect();
-
-            // Try to map those to something more useful
-            let mut missing_items = Vec::with_capacity(missing.len());
+            let hir = self.tcx.hir();
+            let pretty_owner = hir.def_path(owner.def_id).to_string_no_crate_verbose();
 
-            for local_id in missing {
-                let hir_id = HirId { owner, local_id: ItemLocalId::from_u32(local_id) };
+            let missing_items: Vec<_> = (0..=max as u32)
+                .map(|i| ItemLocalId::from_u32(i))
+                .filter(|&local_id| !self.hir_ids_seen.contains(local_id))
+                .map(|local_id| hir.node_to_string(HirId { owner, local_id }))
+                .collect();
 
-                trace!("missing hir id {:#?}", hir_id);
+            let seen_items: Vec<_> = self
+                .hir_ids_seen
+                .iter()
+                .map(|local_id| hir.node_to_string(HirId { owner, local_id }))
+                .collect();
 
-                missing_items.push(format!(
-                    "[local_id: {}, owner: {}]",
-                    local_id,
-                    self.tcx.hir().def_path(owner.def_id).to_string_no_crate_verbose()
-                ));
-            }
             self.error(|| {
                 format!(
                     "ItemLocalIds not assigned densely in {}. \
-                Max ItemLocalId = {}, missing IDs = {:#?}; seens IDs = {:#?}",
-                    self.tcx.hir().def_path(owner.def_id).to_string_no_crate_verbose(),
-                    max,
-                    missing_items,
-                    self.hir_ids_seen
-                        .iter()
-                        .map(|local_id| HirId { owner, local_id })
-                        .map(|h| format!("({:?} {})", h, self.tcx.hir().node_to_string(h)))
-                        .collect::<Vec<_>>()
+                Max ItemLocalId = {}, missing IDs = {:#?}; seen IDs = {:#?}",
+                    pretty_owner, max, missing_items, seen_items
                 )
             });
         }
index 4c6a9b23fdf12a9ed33c99f71337ce81c64364d0..f4da1aaec11301ff44e303f7e8c316f01dcf3478 100644 (file)
@@ -4,7 +4,7 @@
 //! but are not declared in one single location (unlike lang features), which means we need to
 //! collect them instead.
 
-use rustc_ast::{Attribute, MetaItemKind};
+use rustc_ast::Attribute;
 use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER};
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
@@ -42,8 +42,7 @@ fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
         // Find a stability attribute: one of #[stable(…)], #[unstable(…)],
         // #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable].
         if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) {
-            let meta_kind = attr.meta_kind();
-            if let Some(MetaItemKind::List(ref metas)) = meta_kind {
+            if let Some(metas) = attr.meta_item_list() {
                 let mut feature = None;
                 let mut since = None;
                 for meta in metas {
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 6125ad4eff11835e9329ce36c20cdb7f1ce4db35..4dea03c1ef6a260882b3d1ed46a5285c3b7cedb0 100644 (file)
@@ -314,11 +314,14 @@ pub(crate) fn create_query_frame<
     kind: DepKind,
     name: &'static str,
 ) -> QueryStackFrame<DepKind> {
-    // Disable visible paths printing for performance reasons.
-    // Showing visible path instead of any path is not that important in production.
-    let description = ty::print::with_no_visible_paths!(
-        // Force filename-line mode to avoid invoking `type_of` query.
-        ty::print::with_forced_impl_filename_line!(do_describe(tcx.tcx, key))
+    // Avoid calling queries while formatting the description
+    let description = ty::print::with_no_queries!(
+        // Disable visible paths printing for performance reasons.
+        // Showing visible path instead of any path is not that important in production.
+        ty::print::with_no_visible_paths!(
+            // Force filename-line mode to avoid invoking `type_of` query.
+            ty::print::with_forced_impl_filename_line!(do_describe(tcx.tcx, key))
+        )
     );
     let description =
         if tcx.sess.verbose() { format!("{description} [{name:?}]") } else { description };
index 47b2fd8f8f47a4d31da672b7e76c5de3b69d5d2f..9443ded704d63059c8ae48cdd7acc859876ecc74 100644 (file)
@@ -47,7 +47,7 @@ impl DepNodeIndex {
 }
 
 impl From<DepNodeIndex> for QueryInvocationId {
-    #[inline]
+    #[inline(always)]
     fn from(dep_node_index: DepNodeIndex) -> Self {
         QueryInvocationId(dep_node_index.as_u32())
     }
index 77d0d0314fc17de7a36de449436e484118bec350..9f875b4373173cac741bc7fdd5058627de025b0e 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;
-
-    /// Store a value without putting it in the cache.
-    /// This is meant to be used with cycle errors.
-    fn store_nocache(&self, value: Self::Value) -> Self::Stored;
+    type Stored: Copy;
 }
 
 pub trait QueryCache: QueryStorage + Sized {
@@ -36,14 +32,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 +44,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,29 +61,20 @@ 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;
-
-    #[inline]
-    fn store_nocache(&self, value: Self::Value) -> Self::Stored {
-        // We have no dedicated storage
-        value
-    }
 }
 
 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 +82,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]
@@ -159,13 +134,6 @@ fn default() -> Self {
 impl<'tcx, K: Eq + Hash, V: Debug + 'tcx> QueryStorage for ArenaCache<'tcx, K, V> {
     type Value = V;
     type Stored = &'tcx V;
-
-    #[inline]
-    fn store_nocache(&self, value: Self::Value) -> Self::Stored {
-        let value = self.arena.alloc((value, DepNodeIndex::INVALID));
-        let value = unsafe { &*(&value.0 as *const _) };
-        &value
-    }
 }
 
 impl<'tcx, K, V: 'tcx> QueryCache for ArenaCache<'tcx, K, V>
@@ -176,10 +144,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 +152,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 +194,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,39 +211,25 @@ 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;
-
-    #[inline]
-    fn store_nocache(&self, value: Self::Value) -> Self::Stored {
-        // We have no dedicated storage
-        value
-    }
 }
 
 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]
@@ -340,13 +286,6 @@ fn default() -> Self {
 impl<'tcx, K: Eq + Idx, V: Debug + 'tcx> QueryStorage for VecArenaCache<'tcx, K, V> {
     type Value = V;
     type Stored = &'tcx V;
-
-    #[inline]
-    fn store_nocache(&self, value: Self::Value) -> Self::Stored {
-        let value = self.arena.alloc((value, DepNodeIndex::INVALID));
-        let value = unsafe { &*(&value.0 as *const _) };
-        &value
-    }
 }
 
 impl<'tcx, K, V: 'tcx> QueryCache for VecArenaCache<'tcx, K, V>
@@ -357,20 +296,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..ed66d1929c5e78d1843c78fe756f057ce4bf8096 100644 (file)
@@ -121,20 +121,17 @@ struct JobOwner<'tcx, K, D: DepKind>
 
 #[cold]
 #[inline(never)]
-fn mk_cycle<Qcx, V, R, D: DepKind>(
+fn mk_cycle<Qcx, R, D: DepKind>(
     qcx: Qcx,
     cycle_error: CycleError<D>,
     handler: HandleCycleError,
-    cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>,
 ) -> R
 where
     Qcx: QueryContext + crate::query::HasDepContext<DepKind = D>,
-    V: std::fmt::Debug + Value<Qcx::DepContext, Qcx::DepKind>,
-    R: Clone,
+    R: std::fmt::Debug + Value<Qcx::DepContext, Qcx::DepKind>,
 {
     let error = report_cycle(qcx.dep_context().sess(), &cycle_error);
-    let value = handle_cycle_error(*qcx.dep_context(), &cycle_error, error, handler);
-    cache.store_nocache(value)
+    handle_cycle_error(*qcx.dep_context(), &cycle_error, error, handler)
 }
 
 fn handle_cycle_error<Tcx, V>(
@@ -339,25 +336,19 @@ 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()) {
+    match cache.lookup(&key) {
+        Some((value, index)) => {
             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,34 +370,40 @@ 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))
         }
         TryGetJob::Cycle(error) => {
-            let result = mk_cycle(qcx, error, Q::HANDLE_CYCLE_ERROR, cache);
+            let result = mk_cycle(qcx, error, Q::HANDLE_CYCLE_ERROR);
             (result, None)
         }
         #[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());
-            }
+            qcx.dep_context().profiler().query_cache_hit(index.into());
             query_blocked_prof_timer.finish_with_query_invocation_id(index.into());
 
             (v, Some(index))
@@ -771,15 +768,9 @@ 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 std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) {
-            qcx.dep_context().profiler().query_cache_hit(index.into());
-        }
-    });
-
-    match cached {
-        Ok(()) => return,
-        Err(()) => {}
+    if let Some((_, index)) = cache.lookup(&key) {
+        qcx.dep_context().profiler().query_cache_hit(index.into());
+        return;
     }
 
     let state = Q::query_state(qcx);
index 84421dc1f62253354794e3b8079c190213e7d66b..2fb62ce53ba6e357b0f4be8d04eef0fa949b949d 100644 (file)
@@ -265,7 +265,7 @@ fn try_resolve_visibility<'ast>(
                 let ident = path.segments.get(0).expect("empty path in visibility").ident;
                 let crate_root = if ident.is_path_segment_keyword() {
                     None
-                } else if ident.span.rust_2015() {
+                } else if ident.span.is_rust_2015() {
                     Some(Segment::from_ident(Ident::new(
                         kw::PathRoot,
                         path.span.shrink_to_lo().with_ctxt(ident.span.ctxt()),
@@ -435,10 +435,10 @@ fn build_reduced_graph_for_use_tree(
         // appears, so imports in braced groups can have roots prepended independently.
         let is_glob = matches!(use_tree.kind, ast::UseTreeKind::Glob);
         let crate_root = match prefix_iter.peek() {
-            Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => {
+            Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.is_rust_2015() => {
                 Some(seg.ident.span.ctxt())
             }
-            None if is_glob && use_tree.span.rust_2015() => Some(use_tree.span.ctxt()),
+            None if is_glob && use_tree.span.is_rust_2015() => Some(use_tree.span.ctxt()),
             _ => None,
         }
         .map(|ctxt| {
index 3bf041cebcb88a6996b704dce8f2ce409a304cd9..a08ae0f184bb2f62cb7400353a063e6e417ed998 100644 (file)
@@ -462,7 +462,9 @@ pub(crate) fn lint_if_path_starts_with_module(
 
         let first_name = match path.get(0) {
             // In the 2018 edition this lint is a hard error, so nothing to do
-            Some(seg) if seg.ident.span.rust_2015() && self.session.rust_2015() => seg.ident.name,
+            Some(seg) if seg.ident.span.is_rust_2015() && self.session.is_rust_2015() => {
+                seg.ident.name
+            }
             _ => return,
         };
 
@@ -1717,7 +1719,7 @@ pub(crate) fn report_path_resolution_error(
                         Applicability::MaybeIncorrect,
                     )),
                 )
-            } else if self.session.rust_2015() {
+            } else if self.session.is_rust_2015() {
                 (
                     format!("maybe a missing crate `{ident}`?"),
                     Some((
@@ -1996,7 +1998,7 @@ fn make_external_crate_suggestion(
         mut path: Vec<Segment>,
         parent_scope: &ParentScope<'b>,
     ) -> Option<(Vec<Segment>, Option<String>)> {
-        if path[1].ident.span.rust_2015() {
+        if path[1].ident.span.is_rust_2015() {
             return None;
         }
 
index 1c985d43658ae25f1b66acfedfc1ccde9a75cdfa..d03ccf256fad79f2ddc6a1d48e002e821a67e7fe 100644 (file)
@@ -85,7 +85,7 @@ pub(crate) fn visit_scopes<T>(
         // 4c. Standard library prelude (de-facto closed, controlled).
         // 6. Language prelude: builtin attributes (closed, controlled).
 
-        let rust_2015 = ctxt.edition().rust_2015();
+        let rust_2015 = ctxt.edition().is_rust_2015();
         let (ns, macro_kind, is_absolute_path) = match scope_set {
             ScopeSet::All(ns, _) => (ns, None, false),
             ScopeSet::AbsolutePath(ns) => (ns, None, true),
@@ -1397,7 +1397,8 @@ pub(crate) fn resolve_path_with_ribs(
                         module = Some(ModuleOrUniformRoot::ExternPrelude);
                         continue;
                     }
-                    if name == kw::PathRoot && ident.span.rust_2015() && self.session.rust_2018() {
+                    if name == kw::PathRoot && ident.span.is_rust_2015() && self.session.rust_2018()
+                    {
                         // `::a::b` from 2015 macro on 2018 global edition
                         module = Some(ModuleOrUniformRoot::CrateRootAndExternPrelude);
                         continue;
index 83932c089b311afba738f9e3fb9ff652befe1079..3ca10ac50baa6392ed0fcf47f46de5ad34b9871e 100644 (file)
@@ -2145,7 +2145,7 @@ fn future_proof_import(&mut self, use_tree: &UseTree) {
         let segments = &use_tree.prefix.segments;
         if !segments.is_empty() {
             let ident = segments[0].ident;
-            if ident.is_path_segment_keyword() || ident.span.rust_2015() {
+            if ident.is_path_segment_keyword() || ident.span.is_rust_2015() {
                 return;
             }
 
index 37beff37c1fb9d988c33ae968afa86fb96370603..cee0a7f3c203d8e4eeb871f99f978ccfac100839 100644 (file)
@@ -1343,7 +1343,7 @@ fn smart_resolve_context_dependent_help(
                     "!",
                     Applicability::MaybeIncorrect,
                 );
-                if path_str == "try" && span.rust_2015() {
+                if path_str == "try" && span.is_rust_2015() {
                     err.note("if you want the `try` keyword, you need Rust 2018 or later");
                 }
             }
index 1085bce44758fe7235929e8c7ca2b703f23cbae3..55178250472ef94bc08d45ba429ea02f7f83458b 100644 (file)
@@ -19,8 +19,26 @@ pub enum SizeKind {
     Min,
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub enum FieldKind {
+    AdtField,
+    Upvar,
+    GeneratorLocal,
+}
+
+impl std::fmt::Display for FieldKind {
+    fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            FieldKind::AdtField => write!(w, "field"),
+            FieldKind::Upvar => write!(w, "upvar"),
+            FieldKind::GeneratorLocal => write!(w, "local"),
+        }
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub struct FieldInfo {
+    pub kind: FieldKind,
     pub name: Symbol,
     pub offset: u64,
     pub size: u64,
@@ -66,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(),
@@ -145,7 +167,7 @@ pub fn print_type_sizes(&self) {
                 fields.sort_by_key(|f| (f.offset, f.size));
 
                 for field in fields {
-                    let FieldInfo { ref name, offset, size, align } = field;
+                    let FieldInfo { kind, ref name, offset, size, align } = field;
 
                     if offset > min_offset {
                         let pad = offset - min_offset;
@@ -155,16 +177,16 @@ pub fn print_type_sizes(&self) {
                     if offset < min_offset {
                         // If this happens it's probably a union.
                         println!(
-                            "print-type-size {indent}field `.{name}`: {size} bytes, \
+                            "print-type-size {indent}{kind} `.{name}`: {size} bytes, \
                                   offset: {offset} bytes, \
                                   alignment: {align} bytes"
                         );
                     } else if info.packed || offset == min_offset {
-                        println!("print-type-size {indent}field `.{name}`: {size} bytes");
+                        println!("print-type-size {indent}{kind} `.{name}`: {size} bytes");
                     } else {
                         // Include field alignment in output only if it caused padding injection
                         println!(
-                            "print-type-size {indent}field `.{name}`: {size} bytes, \
+                            "print-type-size {indent}{kind} `.{name}`: {size} bytes, \
                                   alignment: {align} bytes"
                         );
                     }
index 3b2cd1864c518e1e3dcebba102cf9aa8095412ad..8a0176f6391743adb6a17ccf30a3fc49223b92b3 100644 (file)
@@ -1,17 +1,9 @@
 use crate::cgu_reuse_tracker::CguReuseTracker;
 use crate::code_stats::CodeStats;
-pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
+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 {
@@ -919,8 +911,8 @@ pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -
     }
 
     /// Is this edition 2015?
-    pub fn rust_2015(&self) -> bool {
-        self.edition().rust_2015()
+    pub fn is_rust_2015(&self) -> bool {
+        self.edition().is_rust_2015()
     }
 
     /// Are we allowed to use features from the Rust 2018 edition?
@@ -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 e66ec07904341b8585d529f82c2d87adc829bbc7..f16db69aae2323d6efef2998b64dc43ee307837a 100644 (file)
@@ -77,7 +77,7 @@ pub fn is_stable(self) -> bool {
     }
 
     /// Is this edition 2015?
-    pub fn rust_2015(self) -> bool {
+    pub fn is_rust_2015(self) -> bool {
         self == Edition::Edition2015
     }
 
index 006102a5f2fcfc471abf0c1523bd1d1f22c029fc..e095cf3fda20d53cef6edd184b5c29d998d74b99 100644 (file)
@@ -705,8 +705,8 @@ pub fn edition(self) -> edition::Edition {
     }
 
     #[inline]
-    pub fn rust_2015(self) -> bool {
-        self.edition().rust_2015()
+    pub fn is_rust_2015(self) -> bool {
+        self.edition().is_rust_2015()
     }
 
     #[inline]
index f1119214be44db4e7d61615bfa9f488253c2f634..1ced75cccbb30251a3a7e918a63ca66e28a72498 100644 (file)
         plugins,
         pointee_trait,
         pointer,
-        pointer_sized,
+        pointer_like,
         poll,
         position,
         post_dash_lto: "post-lto",
index 0009972cf425693c9134e84e5b1cf5e786d54a06..2b135b6703481821fddd80ceabb5c93d863c0d0b 100644 (file)
@@ -2,7 +2,7 @@
 use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let llvm_target = "arm64-apple-ios14.0-macabi";
+    let llvm_target = "arm64-apple-ios-macabi";
 
     let arch = Arch::Arm64_macabi;
     let mut base = opts("ios", arch);
@@ -22,7 +22,7 @@ pub fn target() -> Target {
             // These arguments are not actually invoked - they just have
             // to look right to pass App Store validation.
             bitcode_llvm_cmdline: "-triple\0\
-                arm64-apple-ios14.0-macabi\0\
+                arm64-apple-ios-macabi\0\
                 -emit-obj\0\
                 -disable-llvm-passes\0\
                 -Os\0"
index 0f3f8519963778d172d4ef5b164c100d71da2139..5a3e2a79bb9cc326d3b84f284c9d6aedc8e85910 100644 (file)
@@ -2,7 +2,7 @@
 use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let llvm_target = "x86_64-apple-ios13.0-macabi";
+    let llvm_target = "x86_64-apple-ios-macabi";
 
     let arch = Arch::X86_64_macabi;
     let mut base = opts("ios", arch);
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 5690b6536bbc0b9e8ce7a96414999fed495a5a40..8525b96c0c21ffdf2927a63b6c2ab5822095bd3a 100644 (file)
@@ -81,6 +81,7 @@ pub(super) enum CandidateSource {
     AliasBound,
 }
 
+/// Methods used to assemble candidates for either trait or projection goals.
 pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
     fn self_ty(self) -> Ty<'tcx>;
 
@@ -127,9 +128,9 @@ fn consider_builtin_copy_clone_candidate(
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    // A type is `PointerSized` if we can compute its layout, and that layout
+    // A type is `PointerLike` if we can compute its layout, and that layout
     // matches the layout of `usize`.
-    fn consider_builtin_pointer_sized_candidate(
+    fn consider_builtin_pointer_like_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
@@ -188,6 +189,11 @@ fn consider_builtin_dyn_upcast_candidates(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> Vec<CanonicalResponse<'tcx>>;
+
+    fn consider_builtin_discriminant_kind_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
@@ -306,8 +312,8 @@ fn assemble_builtin_impl_candidates<G: GoalKind<'tcx>>(
             || lang_items.clone_trait() == Some(trait_def_id)
         {
             G::consider_builtin_copy_clone_candidate(self, goal)
-        } else if lang_items.pointer_sized() == Some(trait_def_id) {
-            G::consider_builtin_pointer_sized_candidate(self, goal)
+        } else if lang_items.pointer_like() == Some(trait_def_id) {
+            G::consider_builtin_pointer_like_candidate(self, goal)
         } else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) {
             G::consider_builtin_fn_trait_candidates(self, goal, kind)
         } else if lang_items.tuple_trait() == Some(trait_def_id) {
@@ -320,6 +326,8 @@ fn assemble_builtin_impl_candidates<G: GoalKind<'tcx>>(
             G::consider_builtin_generator_candidate(self, goal)
         } else if lang_items.unsize_trait() == Some(trait_def_id) {
             G::consider_builtin_unsize_candidate(self, goal)
+        } else if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
+            G::consider_builtin_discriminant_kind_candidate(self, goal)
         } else {
             Err(NoSolution)
         };
index a2c15123b4fbd7cbb7e818c0bf6859f76ee845cb..c1936b7dbe41ec0743130a33af65837e39b92345 100644 (file)
@@ -74,7 +74,7 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
                                     )
                                 }
                                 ty::PredicateKind::Subtype(pred) => {
-                                    let (a, b) = infcx.replace_bound_vars_with_placeholders(
+                                    let (a, b) = infcx.instantiate_binder_with_placeholders(
                                         goal.predicate.kind().rebind((pred.a, pred.b)),
                                     );
                                     let expected_found = ExpectedFound::new(true, a, b);
@@ -84,7 +84,7 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
                                     )
                                 }
                                 ty::PredicateKind::Coerce(pred) => {
-                                    let (a, b) = infcx.replace_bound_vars_with_placeholders(
+                                    let (a, b) = infcx.instantiate_binder_with_placeholders(
                                         goal.predicate.kind().rebind((pred.a, pred.b)),
                                     );
                                     let expected_found = ExpectedFound::new(false, a, b);
@@ -94,7 +94,7 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
                                     )
                                 }
                                 ty::PredicateKind::ConstEquate(a, b) => {
-                                    let (a, b) = infcx.replace_bound_vars_with_placeholders(
+                                    let (a, b) = infcx.instantiate_binder_with_placeholders(
                                         goal.predicate.kind().rebind((a, b)),
                                     );
                                     let expected_found = ExpectedFound::new(true, a, b);
index 42f597c781d257e0f97506d931d5121b5d5a83fd..36f987c9f9cb6d3e1a2db0bbcd2e588e9c40c373 100644 (file)
@@ -26,7 +26,7 @@ fn eq<T: ToTrace<'tcx>>(
         rhs: T,
     ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>;
 
-    fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>(
+    fn instantiate_binder_with_infer<T: TypeFoldable<'tcx> + Copy>(
         &self,
         value: ty::Binder<'tcx, T>,
     ) -> T;
@@ -65,11 +65,11 @@ fn eq<T: ToTrace<'tcx>>(
             })
     }
 
-    fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>(
+    fn instantiate_binder_with_infer<T: TypeFoldable<'tcx> + Copy>(
         &self,
         value: ty::Binder<'tcx, T>,
     ) -> T {
-        self.replace_bound_vars_with_fresh_vars(
+        self.instantiate_binder_with_fresh_vars(
             DUMMY_SP,
             LateBoundRegionConversionTime::HigherRankedType,
             value,
index 36170b3788a7a7b0cc5d1cf21badbbf48ae0f261..9f092b6018f483303bc1691784701619f33fff14 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,
@@ -313,7 +304,7 @@ fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult
                 }
             }
         } else {
-            let kind = self.infcx.replace_bound_vars_with_placeholders(kind);
+            let kind = self.infcx.instantiate_binder_with_placeholders(kind);
             let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
             let (_, certainty) = self.evaluate_goal(goal)?;
             self.make_canonical_response(certainty)
@@ -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 a23fdd24b4e42338032bb8bd919a6faec10f5a6a..e3ec71d1b4f7375643eef5d6393af37c1b140675 100644 (file)
@@ -323,7 +323,7 @@ fn consider_assumption(
         {
             ecx.infcx.probe(|_| {
                 let assumption_projection_pred =
-                    ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred);
+                    ecx.infcx.instantiate_binder_with_infer(poly_projection_pred);
                 let nested_goals = ecx.infcx.eq(
                     goal.param_env,
                     goal.predicate.projection_ty,
@@ -370,11 +370,11 @@ fn consider_builtin_copy_clone_candidate(
         bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
     }
 
-    fn consider_builtin_pointer_sized_candidate(
+    fn consider_builtin_pointer_like_candidate(
         _ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        bug!("`PointerSized` does not have an associated type: {:?}", goal);
+        bug!("`PointerLike` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_fn_trait_candidates(
@@ -581,6 +581,15 @@ fn consider_builtin_dyn_upcast_candidates(
     ) -> Vec<super::CanonicalResponse<'tcx>> {
         bug!("`Unsize` does not have an associated type: {:?}", goal);
     }
+
+    fn consider_builtin_discriminant_kind_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let discriminant = goal.predicate.self_ty().discriminant_ty(ecx.tcx());
+        ecx.infcx
+            .probe(|_| ecx.eq_term_and_make_canonical_response(goal, Certainty::Yes, discriminant))
+    }
 }
 
 /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
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 29ee9da38e08be5b391709294baac16b1630236b..06a72e95d4905461814477d70ad25e42d060f91b 100644 (file)
@@ -72,7 +72,7 @@ fn consider_assumption(
             // FIXME: Constness and polarity
             ecx.infcx.probe(|_| {
                 let assumption_trait_pred =
-                    ecx.infcx.instantiate_bound_vars_with_infer(poly_trait_pred);
+                    ecx.infcx.instantiate_binder_with_infer(poly_trait_pred);
                 let nested_goals = ecx.infcx.eq(
                     goal.param_env,
                     goal.predicate.trait_ref,
@@ -131,7 +131,7 @@ fn consider_builtin_copy_clone_candidate(
         )
     }
 
-    fn consider_builtin_pointer_sized_candidate(
+    fn consider_builtin_pointer_like_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
@@ -439,6 +439,14 @@ fn consider_builtin_dyn_upcast_candidates(
 
         responses
     }
+
+    fn consider_builtin_discriminant_kind_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        _goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        // `DiscriminantKind` is automatically implemented for every type.
+        ecx.make_canonical_response(Certainty::Yes)
+    }
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
index 5007a019e1892a3995400c1a7fa8e2550743b284..1ee35a86e626424a3c6a0871f9b84f3f01145423 100644 (file)
@@ -54,7 +54,7 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
         }
 
         ty::GeneratorWitness(types) => {
-            Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
+            Ok(infcx.instantiate_binder_with_placeholders(types).to_vec())
         }
 
         ty::GeneratorWitnessMIR(..) => todo!(),
@@ -174,7 +174,7 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
         }
 
         ty::GeneratorWitness(types) => {
-            Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
+            Ok(infcx.instantiate_binder_with_placeholders(types).to_vec())
         }
 
         ty::GeneratorWitnessMIR(..) => todo!(),
index 6bf453c3ff084376b2afa27c74384acbf4e5a8bd..84045c4d0edea11f5e61f766a0f1bc3cf1f607e8 100644 (file)
@@ -22,7 +22,7 @@ pub fn recompute_applicable_impls<'tcx>(
     let impl_may_apply = |impl_def_id| {
         let ocx = ObligationCtxt::new_in_snapshot(infcx);
         let placeholder_obligation =
-            infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+            infcx.instantiate_binder_with_placeholders(obligation.predicate);
         let obligation_trait_ref =
             ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
 
@@ -47,11 +47,11 @@ pub fn recompute_applicable_impls<'tcx>(
     let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| {
         let ocx = ObligationCtxt::new_in_snapshot(infcx);
         let placeholder_obligation =
-            infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+            infcx.instantiate_binder_with_placeholders(obligation.predicate);
         let obligation_trait_ref =
             ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
 
-        let param_env_predicate = infcx.replace_bound_vars_with_fresh_vars(
+        let param_env_predicate = infcx.instantiate_binder_with_fresh_vars(
             DUMMY_SP,
             LateBoundRegionConversionTime::HigherRankedType,
             poly_trait_predicate,
index f6d0b9713f0d0ca1d03da77d4e798516beee410e..cf1e05ada4713615087d28181215dd5dd9d95660 100644 (file)
@@ -1716,7 +1716,7 @@ fn report_projection_error(
             let (values, err) = if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) =
                 bound_predicate.skip_binder()
             {
-                let data = self.replace_bound_vars_with_fresh_vars(
+                let data = self.instantiate_binder_with_fresh_vars(
                     obligation.cause.span,
                     infer::LateBoundRegionConversionTime::HigherRankedType,
                     bound_predicate.rebind(data),
index b35b9d62759c73267bf4d3f217616a6305b23592..59aef52910ee3f287b359383db57b2fcb1e31d61 100644 (file)
@@ -133,7 +133,7 @@ fn get_from_await_ty<F>(
                                         .cloned()
                                         .unwrap_or_else(|| {
                                             bug!(
-                                                "node_type: no type for node `{}`",
+                                                "node_type: no type for node {}",
                                                 ty::tls::with(|tcx| tcx
                                                     .hir()
                                                     .node_to_string(await_expr.hir_id))
@@ -679,6 +679,7 @@ fn suggest_restricting_param_bound(
                         &param_name,
                         &constraint,
                         Some(trait_pred.def_id()),
+                        None,
                     ) {
                         return;
                     }
@@ -897,7 +898,7 @@ fn suggest_fn_call(
             return false;
         }
 
-        let self_ty = self.replace_bound_vars_with_fresh_vars(
+        let self_ty = self.instantiate_binder_with_fresh_vars(
             DUMMY_SP,
             LateBoundRegionConversionTime::FnCall,
             trait_pred.self_ty(),
@@ -1087,6 +1088,7 @@ fn suggest_add_clone_to_arg(
                     param.name.as_str(),
                     "Clone",
                     Some(clone_trait),
+                    None,
                 );
             }
             err.span_suggestion_verbose(
@@ -1189,7 +1191,7 @@ fn extract_callable_info(
             }
         }) else { return None; };
 
-        let output = self.replace_bound_vars_with_fresh_vars(
+        let output = self.instantiate_binder_with_fresh_vars(
             DUMMY_SP,
             LateBoundRegionConversionTime::FnCall,
             output,
@@ -1198,7 +1200,7 @@ fn extract_callable_info(
             .skip_binder()
             .iter()
             .map(|ty| {
-                self.replace_bound_vars_with_fresh_vars(
+                self.instantiate_binder_with_fresh_vars(
                     DUMMY_SP,
                     LateBoundRegionConversionTime::FnCall,
                     inputs.rebind(*ty),
@@ -3804,13 +3806,13 @@ fn hint_missing_borrow<'tcx>(
     err: &mut Diagnostic,
 ) {
     let found_args = match found.kind() {
-        ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
+        ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(),
         kind => {
             span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
         }
     };
     let expected_args = match expected.kind() {
-        ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
+        ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(),
         kind => {
             span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
         }
index 18d30771035fdbcebf4bdf961ff9bbccd2993ed1..3adc1e62e0d4853368bb663dba6e88d5f978431d 100644 (file)
@@ -321,7 +321,7 @@ fn process_obligation(
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..) => {
                     let pred =
-                        ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder));
+                        ty::Binder::dummy(infcx.instantiate_binder_with_placeholders(binder));
                     ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)]))
                 }
                 ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
index 565cfca9090e19c2c5e41d7d24fd0eb874661733..8f548acfd2eaccc8834f326f04cb201dcefd8e6d 100644 (file)
@@ -547,16 +547,56 @@ fn virtual_call_violation_for_method<'tcx>(
 
     // NOTE: This check happens last, because it results in a lint, and not a
     // hard error.
-    if tcx
-        .predicates_of(method.def_id)
-        .predicates
-        .iter()
-        // A trait object can't claim to live more than the concrete type,
-        // so outlives predicates will always hold.
-        .cloned()
-        .filter(|(p, _)| p.to_opt_type_outlives().is_none())
-        .any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
-    {
+    if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, span)| {
+        // dyn Trait is okay:
+        //
+        //     trait Trait {
+        //         fn f(&self) where Self: 'static;
+        //     }
+        //
+        // because a trait object can't claim to live longer than the concrete
+        // type. If the lifetime bound holds on dyn Trait then it's guaranteed
+        // to hold as well on the concrete type.
+        if pred.to_opt_type_outlives().is_some() {
+            return false;
+        }
+
+        // dyn Trait is okay:
+        //
+        //     auto trait AutoTrait {}
+        //
+        //     trait Trait {
+        //         fn f(&self) where Self: AutoTrait;
+        //     }
+        //
+        // because `impl AutoTrait for dyn Trait` is disallowed by coherence.
+        // Traits with a default impl are implemented for a trait object if and
+        // only if the autotrait is one of the trait object's trait bounds, like
+        // in `dyn Trait + AutoTrait`. This guarantees that trait objects only
+        // implement auto traits if the underlying type does as well.
+        if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
+            trait_ref: pred_trait_ref,
+            constness: ty::BoundConstness::NotConst,
+            polarity: ty::ImplPolarity::Positive,
+        })) = pred.kind().skip_binder()
+            && pred_trait_ref.self_ty() == tcx.types.self_param
+            && tcx.trait_is_auto(pred_trait_ref.def_id)
+        {
+            // Consider bounds like `Self: Bound<Self>`. Auto traits are not
+            // allowed to have generic parameters so `auto trait Bound<T> {}`
+            // would already have reported an error at the definition of the
+            // auto trait.
+            if pred_trait_ref.substs.len() != 1 {
+                tcx.sess.diagnostic().delay_span_bug(
+                    span,
+                    "auto traits cannot have generic parameters",
+                );
+            }
+            return false;
+        }
+
+        contains_illegal_self_type_reference(tcx, trait_def_id, pred.clone())
+    }) {
         return Some(MethodViolationCode::WhereClauseReferencesSelf);
     }
 
index 53cae3e720c5ae6e2ac1fd70a634c53202223d03..aa81bc640aa6c56367e4e9cdf87abf9e7e73984e 100644 (file)
@@ -215,7 +215,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
     let r = infcx.commit_if_ok(|_snapshot| {
         let old_universe = infcx.universe();
         let placeholder_predicate =
-            infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+            infcx.instantiate_binder_with_placeholders(obligation.predicate);
         let new_universe = infcx.universe();
 
         let placeholder_obligation = obligation.with(infcx.tcx, placeholder_predicate);
@@ -2046,7 +2046,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
     let cause = &obligation.cause;
     let param_env = obligation.param_env;
 
-    let cache_entry = infcx.replace_bound_vars_with_fresh_vars(
+    let cache_entry = infcx.instantiate_binder_with_fresh_vars(
         cause.span,
         LateBoundRegionConversionTime::HigherRankedType,
         poly_cache_entry,
index 7b7abcf552ab7da31b513f5346fbad37e814113a..e9f7c3bc4cca2ecb93a54bb13e454f2e46d12818 100644 (file)
@@ -94,7 +94,7 @@ pub(super) fn assemble_candidates<'o>(
                 self.assemble_candidates_for_transmutability(obligation, &mut candidates);
             } else if lang_items.tuple_trait() == Some(def_id) {
                 self.assemble_candidate_for_tuple(obligation, &mut candidates);
-            } else if lang_items.pointer_sized() == Some(def_id) {
+            } else if lang_items.pointer_like() == Some(def_id) {
                 self.assemble_candidate_for_ptr_sized(obligation, &mut candidates);
             } else {
                 if lang_items.clone_trait() == Some(def_id) {
@@ -488,7 +488,7 @@ fn assemble_candidates_from_object_ty(
 
             let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
             let placeholder_trait_predicate =
-                self.infcx.replace_bound_vars_with_placeholders(poly_trait_predicate);
+                self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate);
 
             // Count only those upcast versions that match the trait-ref
             // we are looking for. Specifically, do not only check for the
index 0a4136dc1cfe5f508c252874cf7be7fe43cbd259..fcc4820c2a6b6ff424131ceaac1a69ec4b5399a8 100644 (file)
@@ -151,7 +151,7 @@ fn confirm_projection_candidate(
 
         let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
         let placeholder_trait_predicate =
-            self.infcx.replace_bound_vars_with_placeholders(trait_predicate).trait_ref;
+            self.infcx.instantiate_binder_with_placeholders(trait_predicate).trait_ref;
         let placeholder_self_ty = placeholder_trait_predicate.self_ty();
         let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
         let (def_id, substs) = match *placeholder_self_ty.kind() {
@@ -336,7 +336,7 @@ fn vtable_auto_impl(
             let cause = obligation.derived_cause(BuiltinDerivedObligation);
 
             let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
-            let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
+            let trait_ref = self.infcx.instantiate_binder_with_placeholders(poly_trait_ref);
             let trait_obligations: Vec<PredicateObligation<'_>> = self.impl_or_trait_obligations(
                 &cause,
                 obligation.recursion_depth + 1,
@@ -427,7 +427,7 @@ fn confirm_object_candidate(
         let tcx = self.tcx();
         debug!(?obligation, ?index, "confirm_object_candidate");
 
-        let trait_predicate = self.infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+        let trait_predicate = self.infcx.instantiate_binder_with_placeholders(obligation.predicate);
         let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty());
         let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref);
         let ty::Dynamic(data, ..) = *self_ty.kind() else {
@@ -437,7 +437,7 @@ fn confirm_object_candidate(
         let object_trait_ref = data.principal().unwrap_or_else(|| {
             span_bug!(obligation.cause.span, "object candidate with no principal")
         });
-        let object_trait_ref = self.infcx.replace_bound_vars_with_fresh_vars(
+        let object_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
             obligation.cause.span,
             HigherRankedType,
             object_trait_ref,
@@ -629,7 +629,7 @@ fn confirm_fn_pointer_candidate(
         }
 
         // Confirm the `type Output: Sized;` bound that is present on `FnOnce`
-        let output_ty = self.infcx.replace_bound_vars_with_placeholders(sig.output());
+        let output_ty = self.infcx.instantiate_binder_with_placeholders(sig.output());
         let output_ty = normalize_with_depth_to(
             self,
             obligation.param_env,
@@ -652,7 +652,7 @@ fn confirm_trait_alias_candidate(
         debug!(?obligation, "confirm_trait_alias_candidate");
 
         let alias_def_id = obligation.predicate.def_id();
-        let predicate = self.infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+        let predicate = self.infcx.instantiate_binder_with_placeholders(obligation.predicate);
         let trait_ref = predicate.trait_ref;
         let trait_def_id = trait_ref.def_id;
         let substs = trait_ref.substs;
@@ -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..984d6fde2686c58384a99a272062b95191794f84 100644 (file)
@@ -1618,7 +1618,7 @@ fn match_projection_obligation_against_definition_bounds(
     ) -> smallvec::SmallVec<[(usize, ty::BoundConstness); 2]> {
         let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
         let placeholder_trait_predicate =
-            self.infcx.replace_bound_vars_with_placeholders(poly_trait_predicate);
+            self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate);
         debug!(?placeholder_trait_predicate);
 
         let tcx = self.infcx.tcx;
@@ -1738,7 +1738,7 @@ pub(super) fn match_projection_projections(
         potentially_unnormalized_candidates: bool,
     ) -> ProjectionMatchesProjection {
         let mut nested_obligations = Vec::new();
-        let infer_predicate = self.infcx.replace_bound_vars_with_fresh_vars(
+        let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars(
             obligation.cause.span,
             LateBoundRegionConversionTime::HigherRankedType,
             env_predicate,
@@ -2339,7 +2339,7 @@ fn collect_predicates_for_types(
             .flat_map(|ty| {
                 let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/
 
-                let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty);
+                let placeholder_ty = self.infcx.instantiate_binder_with_placeholders(ty);
                 let Normalized { value: normalized_ty, mut obligations } =
                     ensure_sufficient_stack(|| {
                         project::normalize_with_depth(
@@ -2418,7 +2418,7 @@ fn match_impl(
         obligation: &TraitObligation<'tcx>,
     ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
         let placeholder_obligation =
-            self.infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+            self.infcx.instantiate_binder_with_placeholders(obligation.predicate);
         let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
 
         let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
@@ -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 378cd5a99ed864ce3bdd23a2fbb20d2216109ac1..2aeb255c1641c61b6329110582aa8bd8ea06808d 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_middle::ty::{
     self, subst::SubstsRef, AdtDef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeVisitable,
 };
-use rustc_session::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
+use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
 use rustc_span::symbol::Symbol;
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::*;
@@ -881,6 +881,7 @@ fn variant_info_for_adt<'tcx>(
                 let offset = layout.fields.offset(i);
                 min_size = min_size.max(offset + field_layout.size);
                 FieldInfo {
+                    kind: FieldKind::AdtField,
                     name,
                     offset: offset.bytes(),
                     size: field_layout.size.bytes(),
@@ -960,6 +961,7 @@ fn variant_info_for_generator<'tcx>(
             let offset = layout.fields.offset(field_idx);
             upvars_size = upvars_size.max(offset + field_layout.size);
             FieldInfo {
+                kind: FieldKind::Upvar,
                 name: Symbol::intern(&name),
                 offset: offset.bytes(),
                 size: field_layout.size.bytes(),
@@ -968,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)| {
@@ -983,6 +985,7 @@ fn variant_info_for_generator<'tcx>(
                     // The struct is as large as the last field's end
                     variant_size = variant_size.max(offset + field_layout.size);
                     FieldInfo {
+                        kind: FieldKind::GeneratorLocal,
                         name: state_specific_names.get(*local).copied().flatten().unwrap_or(
                             Symbol::intern(&format!(".generator_field{}", local.as_usize())),
                         ),
@@ -1030,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 e7bb30553736c492533962e8f576f1101a43e87b..3ede95e84313dde8cdc4e15a01dd8d4693bb6e3a 100644 (file)
@@ -310,47 +310,51 @@ fn clone(&self) -> Self {
 impl<I: Interner> PartialEq for TyKind<I> {
     #[inline]
     fn eq(&self, other: &TyKind<I>) -> bool {
-        tykind_discriminant(self) == tykind_discriminant(other)
-            && match (self, other) {
-                (Int(a_i), Int(b_i)) => a_i == b_i,
-                (Uint(a_u), Uint(b_u)) => a_u == b_u,
-                (Float(a_f), Float(b_f)) => a_f == b_f,
-                (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s,
-                (Foreign(a_d), Foreign(b_d)) => a_d == b_d,
-                (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c,
-                (Slice(a_t), Slice(b_t)) => a_t == b_t,
-                (RawPtr(a_t), RawPtr(b_t)) => a_t == b_t,
-                (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m,
-                (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s,
-                (FnPtr(a_s), FnPtr(b_s)) => a_s == b_s,
-                (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => {
-                    a_p == b_p && a_r == b_r && a_repr == b_repr
-                }
-                (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s,
-                (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => {
-                    a_d == b_d && a_s == b_s && a_m == b_m
-                }
-                (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g,
-                (
-                    &GeneratorWitnessMIR(ref a_d, ref a_s),
-                    &GeneratorWitnessMIR(ref b_d, ref b_s),
-                ) => a_d == b_d && a_s == b_s,
-                (Tuple(a_t), Tuple(b_t)) => a_t == b_t,
-                (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p,
-                (Param(a_p), Param(b_p)) => a_p == b_p,
-                (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b,
-                (Placeholder(a_p), Placeholder(b_p)) => a_p == b_p,
-                (Infer(a_t), Infer(b_t)) => a_t == b_t,
-                (Error(a_e), Error(b_e)) => a_e == b_e,
-                (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => true,
-                _ => {
-                    debug_assert!(
-                        false,
-                        "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"
-                    );
-                    true
-                }
+        // You might expect this `match` to be preceded with this:
+        //
+        //   tykind_discriminant(self) == tykind_discriminant(other) &&
+        //
+        // but the data patterns in practice are such that a comparison
+        // succeeds 99%+ of the time, and it's faster to omit it.
+        match (self, other) {
+            (Int(a_i), Int(b_i)) => a_i == b_i,
+            (Uint(a_u), Uint(b_u)) => a_u == b_u,
+            (Float(a_f), Float(b_f)) => a_f == b_f,
+            (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s,
+            (Foreign(a_d), Foreign(b_d)) => a_d == b_d,
+            (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c,
+            (Slice(a_t), Slice(b_t)) => a_t == b_t,
+            (RawPtr(a_t), RawPtr(b_t)) => a_t == b_t,
+            (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m,
+            (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s,
+            (FnPtr(a_s), FnPtr(b_s)) => a_s == b_s,
+            (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => {
+                a_p == b_p && a_r == b_r && a_repr == b_repr
             }
+            (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s,
+            (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => {
+                a_d == b_d && a_s == b_s && a_m == b_m
+            }
+            (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g,
+            (&GeneratorWitnessMIR(ref a_d, ref a_s), &GeneratorWitnessMIR(ref b_d, ref b_s)) => {
+                a_d == b_d && a_s == b_s
+            }
+            (Tuple(a_t), Tuple(b_t)) => a_t == b_t,
+            (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p,
+            (Param(a_p), Param(b_p)) => a_p == b_p,
+            (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b,
+            (Placeholder(a_p), Placeholder(b_p)) => a_p == b_p,
+            (Infer(a_t), Infer(b_t)) => a_t == b_t,
+            (Error(a_e), Error(b_e)) => a_e == b_e,
+            (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => true,
+            _ => {
+                debug_assert!(
+                    tykind_discriminant(self) != tykind_discriminant(other),
+                    "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"
+                );
+                false
+            }
+        }
     }
 }
 
@@ -408,7 +412,7 @@ fn cmp(&self, other: &TyKind<I>) -> Ordering {
                 (Error(a_e), Error(b_e)) => a_e.cmp(b_e),
                 (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => Ordering::Equal,
                 _ => {
-                    debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}");
+                    debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}");
                     Ordering::Equal
                 }
             }
index 85f058f3664e3e5d388643fb86e70feeca400f83..df4478bb0cb85ac75cfb31fbc78349d30fcfa96b 100644 (file)
@@ -662,7 +662,8 @@ changelog-seen = 2
 
 # Select LTO mode that will be used for compiling rustc. By default, thin local LTO
 # (LTO within a single crate) is used (like for any Rust crate). You can also select
-# "thin" or "fat" to apply Thin/Fat LTO to the `rustc_driver` dylib.
+# "thin" or "fat" to apply Thin/Fat LTO to the `rustc_driver` dylib, or "off" to disable
+# LTO entirely.
 #lto = "thin-local"
 
 # =============================================================================
index 016f139a501a00da5749e941e4c1d47df2fdaccb..000b9bd0fab42408a790d5b811c06f94385eba8a 100644 (file)
@@ -41,6 +41,28 @@ pub unsafe fn awaken(self) -> &'a mut T {
         // SAFETY: our own safety conditions imply this reference is again unique.
         unsafe { &mut *self.ptr.as_ptr() }
     }
+
+    /// Borrows a new mutable reference from the unique borrow initially captured.
+    ///
+    /// # Safety
+    ///
+    /// The reborrow must have ended, i.e., the reference returned by `new` and
+    /// all pointers and references derived from it, must not be used anymore.
+    pub unsafe fn reborrow(&mut self) -> &'a mut T {
+        // SAFETY: our own safety conditions imply this reference is again unique.
+        unsafe { &mut *self.ptr.as_ptr() }
+    }
+
+    /// Borrows a new shared reference from the unique borrow initially captured.
+    ///
+    /// # Safety
+    ///
+    /// The reborrow must have ended, i.e., the reference returned by `new` and
+    /// all pointers and references derived from it, must not be used anymore.
+    pub unsafe fn reborrow_shared(&self) -> &'a T {
+        // SAFETY: our own safety conditions imply this reference is again unique.
+        unsafe { &*self.ptr.as_ptr() }
+    }
 }
 
 #[cfg(test)]
index 1d9c4460ec92a9537f9b7cf8c86a634cc7829474..386cd1a1657e26f0dd9934dee92af16020cfe9fa 100644 (file)
@@ -6,7 +6,7 @@
 use core::iter::{FromIterator, FusedIterator};
 use core::marker::PhantomData;
 use core::mem::{self, ManuallyDrop};
-use core::ops::{Index, RangeBounds};
+use core::ops::{Bound, Index, RangeBounds};
 use core::ptr;
 
 use crate::alloc::{Allocator, Global};
@@ -15,7 +15,7 @@
 use super::dedup_sorted_iter::DedupSortedIter;
 use super::navigate::{LazyLeafRange, LeafRange};
 use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root};
-use super::search::SearchResult::*;
+use super::search::{SearchBound, SearchResult::*};
 use super::set_val::SetValZST;
 
 mod entry;
@@ -2422,6 +2422,732 @@ pub const fn len(&self) -> usize {
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
+
+    /// Returns a [`Cursor`] pointing at the first element that is above the
+    /// given bound.
+    ///
+    /// If no such element exists then a cursor pointing at the "ghost"
+    /// non-element is returned.
+    ///
+    /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first
+    /// element of the map.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(btree_cursors)]
+    ///
+    /// use std::collections::BTreeMap;
+    /// use std::ops::Bound;
+    ///
+    /// let mut a = BTreeMap::new();
+    /// a.insert(1, "a");
+    /// a.insert(2, "b");
+    /// a.insert(3, "c");
+    /// a.insert(4, "c");
+    /// let cursor = a.lower_bound(Bound::Excluded(&2));
+    /// assert_eq!(cursor.key(), Some(&3));
+    /// ```
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn lower_bound<Q>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
+    where
+        K: Borrow<Q> + Ord,
+        Q: Ord,
+    {
+        let root_node = match self.root.as_ref() {
+            None => return Cursor { current: None, root: None },
+            Some(root) => root.reborrow(),
+        };
+        let edge = root_node.lower_bound(SearchBound::from_range(bound));
+        Cursor { current: edge.next_kv().ok(), root: self.root.as_ref() }
+    }
+
+    /// Returns a [`CursorMut`] pointing at the first element that is above the
+    /// given bound.
+    ///
+    /// If no such element exists then a cursor pointing at the "ghost"
+    /// non-element is returned.
+    ///
+    /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first
+    /// element of the map.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(btree_cursors)]
+    ///
+    /// use std::collections::BTreeMap;
+    /// use std::ops::Bound;
+    ///
+    /// let mut a = BTreeMap::new();
+    /// a.insert(1, "a");
+    /// a.insert(2, "b");
+    /// a.insert(3, "c");
+    /// a.insert(4, "c");
+    /// let cursor = a.lower_bound_mut(Bound::Excluded(&2));
+    /// assert_eq!(cursor.key(), Some(&3));
+    /// ```
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn lower_bound_mut<Q>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
+    where
+        K: Borrow<Q> + Ord,
+        Q: Ord,
+    {
+        let (root, dormant_root) = DormantMutRef::new(&mut self.root);
+        let root_node = match root.as_mut() {
+            None => {
+                return CursorMut {
+                    current: None,
+                    root: dormant_root,
+                    length: &mut self.length,
+                    alloc: &mut *self.alloc,
+                };
+            }
+            Some(root) => root.borrow_mut(),
+        };
+        let edge = root_node.lower_bound(SearchBound::from_range(bound));
+        CursorMut {
+            current: edge.next_kv().ok(),
+            root: dormant_root,
+            length: &mut self.length,
+            alloc: &mut *self.alloc,
+        }
+    }
+
+    /// Returns a [`Cursor`] pointing at the last element that is below the
+    /// given bound.
+    ///
+    /// If no such element exists then a cursor pointing at the "ghost"
+    /// non-element is returned.
+    ///
+    /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last
+    /// element of the map.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(btree_cursors)]
+    ///
+    /// use std::collections::BTreeMap;
+    /// use std::ops::Bound;
+    ///
+    /// let mut a = BTreeMap::new();
+    /// a.insert(1, "a");
+    /// a.insert(2, "b");
+    /// a.insert(3, "c");
+    /// a.insert(4, "c");
+    /// let cursor = a.upper_bound(Bound::Excluded(&3));
+    /// assert_eq!(cursor.key(), Some(&2));
+    /// ```
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn upper_bound<Q>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
+    where
+        K: Borrow<Q> + Ord,
+        Q: Ord,
+    {
+        let root_node = match self.root.as_ref() {
+            None => return Cursor { current: None, root: None },
+            Some(root) => root.reborrow(),
+        };
+        let edge = root_node.upper_bound(SearchBound::from_range(bound));
+        Cursor { current: edge.next_back_kv().ok(), root: self.root.as_ref() }
+    }
+
+    /// Returns a [`CursorMut`] pointing at the last element that is below the
+    /// given bound.
+    ///
+    /// If no such element exists then a cursor pointing at the "ghost"
+    /// non-element is returned.
+    ///
+    /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last
+    /// element of the map.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(btree_cursors)]
+    ///
+    /// use std::collections::BTreeMap;
+    /// use std::ops::Bound;
+    ///
+    /// let mut a = BTreeMap::new();
+    /// a.insert(1, "a");
+    /// a.insert(2, "b");
+    /// a.insert(3, "c");
+    /// a.insert(4, "c");
+    /// let cursor = a.upper_bound_mut(Bound::Excluded(&3));
+    /// assert_eq!(cursor.key(), Some(&2));
+    /// ```
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn upper_bound_mut<Q>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
+    where
+        K: Borrow<Q> + Ord,
+        Q: Ord,
+    {
+        let (root, dormant_root) = DormantMutRef::new(&mut self.root);
+        let root_node = match root.as_mut() {
+            None => {
+                return CursorMut {
+                    current: None,
+                    root: dormant_root,
+                    length: &mut self.length,
+                    alloc: &mut *self.alloc,
+                };
+            }
+            Some(root) => root.borrow_mut(),
+        };
+        let edge = root_node.upper_bound(SearchBound::from_range(bound));
+        CursorMut {
+            current: edge.next_back_kv().ok(),
+            root: dormant_root,
+            length: &mut self.length,
+            alloc: &mut *self.alloc,
+        }
+    }
+}
+
+/// A cursor over a `BTreeMap`.
+///
+/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth.
+///
+/// Cursors always point to an element in the tree, and index in a logically circular way.
+/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and
+/// first elements of the tree.
+///
+/// A `Cursor` is created with the [`BTreeMap::lower_bound`] and [`BTreeMap::upper_bound`] methods.
+#[unstable(feature = "btree_cursors", issue = "107540")]
+pub struct Cursor<'a, K: 'a, V: 'a> {
+    current: Option<Handle<NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>, marker::KV>>,
+    root: Option<&'a node::Root<K, V>>,
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl<K, V> Clone for Cursor<'_, K, V> {
+    fn clone(&self) -> Self {
+        let Cursor { current, root } = *self;
+        Cursor { current, root }
+    }
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl<K: Debug, V: Debug> Debug for Cursor<'_, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("Cursor").field(&self.key_value()).finish()
+    }
+}
+
+/// A cursor over a `BTreeMap` with editing operations.
+///
+/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can
+/// safely mutate the tree during iteration. This is because the lifetime of its yielded
+/// references is tied to its own lifetime, instead of just the underlying tree. This means
+/// cursors cannot yield multiple elements at once.
+///
+/// Cursors always point to an element in the tree, and index in a logically circular way.
+/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and
+/// first elements of the tree.
+///
+/// A `Cursor` is created with the [`BTreeMap::lower_bound_mut`] and [`BTreeMap::upper_bound_mut`]
+/// methods.
+#[unstable(feature = "btree_cursors", issue = "107540")]
+pub struct CursorMut<
+    'a,
+    K: 'a,
+    V: 'a,
+    #[unstable(feature = "allocator_api", issue = "32838")] A = Global,
+> {
+    current: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>>,
+    root: DormantMutRef<'a, Option<node::Root<K, V>>>,
+    length: &'a mut usize,
+    alloc: &'a mut A,
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl<K: Debug, V: Debug, A> Debug for CursorMut<'_, K, V, A> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("CursorMut").field(&self.key_value()).finish()
+    }
+}
+
+impl<'a, K, V> Cursor<'a, K, V> {
+    /// Moves the cursor to the next element of the `BTreeMap`.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this will move it to
+    /// the first element of the `BTreeMap`. If it is pointing to the last
+    /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn move_next(&mut self) {
+        match self.current.take() {
+            None => {
+                self.current = self.root.and_then(|root| {
+                    root.reborrow().first_leaf_edge().forget_node_type().right_kv().ok()
+                });
+            }
+            Some(current) => {
+                self.current = current.next_leaf_edge().next_kv().ok();
+            }
+        }
+    }
+
+    /// Moves the cursor to the previous element of the `BTreeMap`.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this will move it to
+    /// the last element of the `BTreeMap`. If it is pointing to the first
+    /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn move_prev(&mut self) {
+        match self.current.take() {
+            None => {
+                self.current = self.root.and_then(|root| {
+                    root.reborrow().last_leaf_edge().forget_node_type().left_kv().ok()
+                });
+            }
+            Some(current) => {
+                self.current = current.next_back_leaf_edge().next_back_kv().ok();
+            }
+        }
+    }
+
+    /// Returns a reference to the key of the element that the cursor is
+    /// currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn key(&self) -> Option<&'a K> {
+        self.current.as_ref().map(|current| current.into_kv().0)
+    }
+
+    /// Returns a reference to the value of the element that the cursor is
+    /// currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn value(&self) -> Option<&'a V> {
+        self.current.as_ref().map(|current| current.into_kv().1)
+    }
+
+    /// Returns a reference to the key and value of the element that the cursor
+    /// is currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn key_value(&self) -> Option<(&'a K, &'a V)> {
+        self.current.as_ref().map(|current| current.into_kv())
+    }
+
+    /// Returns a reference to the next element.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this returns
+    /// the first element of the `BTreeMap`. If it is pointing to the last
+    /// element of the `BTreeMap` then this returns `None`.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_next(&self) -> Option<(&'a K, &'a V)> {
+        let mut next = self.clone();
+        next.move_next();
+        next.current.as_ref().map(|current| current.into_kv())
+    }
+
+    /// Returns a reference to the previous element.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this returns
+    /// the last element of the `BTreeMap`. If it is pointing to the first
+    /// element of the `BTreeMap` then this returns `None`.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_prev(&self) -> Option<(&'a K, &'a V)> {
+        let mut prev = self.clone();
+        prev.move_prev();
+        prev.current.as_ref().map(|current| current.into_kv())
+    }
+}
+
+impl<'a, K, V, A> CursorMut<'a, K, V, A> {
+    /// Moves the cursor to the next element of the `BTreeMap`.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this will move it to
+    /// the first element of the `BTreeMap`. If it is pointing to the last
+    /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn move_next(&mut self) {
+        match self.current.take() {
+            None => {
+                // SAFETY: The previous borrow of root has ended.
+                self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| {
+                    root.borrow_mut().first_leaf_edge().forget_node_type().right_kv().ok()
+                });
+            }
+            Some(current) => {
+                self.current = current.next_leaf_edge().next_kv().ok();
+            }
+        }
+    }
+
+    /// Moves the cursor to the previous element of the `BTreeMap`.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this will move it to
+    /// the last element of the `BTreeMap`. If it is pointing to the first
+    /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn move_prev(&mut self) {
+        match self.current.take() {
+            None => {
+                // SAFETY: The previous borrow of root has ended.
+                self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| {
+                    root.borrow_mut().last_leaf_edge().forget_node_type().left_kv().ok()
+                });
+            }
+            Some(current) => {
+                self.current = current.next_back_leaf_edge().next_back_kv().ok();
+            }
+        }
+    }
+
+    /// Returns a reference to the key of the element that the cursor is
+    /// currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn key(&self) -> Option<&K> {
+        self.current.as_ref().map(|current| current.reborrow().into_kv().0)
+    }
+
+    /// Returns a reference to the value of the element that the cursor is
+    /// currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn value(&self) -> Option<&V> {
+        self.current.as_ref().map(|current| current.reborrow().into_kv().1)
+    }
+
+    /// Returns a reference to the key and value of the element that the cursor
+    /// is currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn key_value(&self) -> Option<(&K, &V)> {
+        self.current.as_ref().map(|current| current.reborrow().into_kv())
+    }
+
+    /// Returns a mutable reference to the value of the element that the cursor
+    /// is currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn value_mut(&mut self) -> Option<&mut V> {
+        self.current.as_mut().map(|current| current.kv_mut().1)
+    }
+
+    /// Returns a reference to the key and mutable reference to the value of the
+    /// element that the cursor is currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn key_value_mut(&mut self) -> Option<(&K, &mut V)> {
+        self.current.as_mut().map(|current| {
+            let (k, v) = current.kv_mut();
+            (&*k, v)
+        })
+    }
+
+    /// Returns a mutable reference to the of the element that the cursor is
+    /// currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    ///
+    /// # Safety
+    ///
+    /// This can be used to modify the key, but you must ensure that the
+    /// `BTreeMap` invariants are maintained. Specifically:
+    ///
+    /// * The key must remain unique within the tree.
+    /// * The key must remain in sorted order with regards to other elements in
+    ///   the tree.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn key_mut_unchecked(&mut self) -> Option<&mut K> {
+        self.current.as_mut().map(|current| current.kv_mut().0)
+    }
+
+    /// Returns a reference to the key and value of the next element.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this returns
+    /// the first element of the `BTreeMap`. If it is pointing to the last
+    /// element of the `BTreeMap` then this returns `None`.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_next(&mut self) -> Option<(&K, &mut V)> {
+        let (k, v) = match self.current {
+            None => {
+                // SAFETY: The previous borrow of root has ended.
+                unsafe { self.root.reborrow() }
+                    .as_mut()?
+                    .borrow_mut()
+                    .first_leaf_edge()
+                    .next_kv()
+                    .ok()?
+                    .into_kv_valmut()
+            }
+            // SAFETY: We're not using this to mutate the tree.
+            Some(ref mut current) => {
+                unsafe { current.reborrow_mut() }.next_leaf_edge().next_kv().ok()?.into_kv_valmut()
+            }
+        };
+        Some((k, v))
+    }
+
+    /// Returns a reference to the key and value of the previous element.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this returns
+    /// the last element of the `BTreeMap`. If it is pointing to the first
+    /// element of the `BTreeMap` then this returns `None`.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_prev(&mut self) -> Option<(&K, &mut V)> {
+        let (k, v) = match self.current.as_mut() {
+            None => {
+                // SAFETY: The previous borrow of root has ended.
+                unsafe { self.root.reborrow() }
+                    .as_mut()?
+                    .borrow_mut()
+                    .first_leaf_edge()
+                    .next_kv()
+                    .ok()?
+                    .into_kv_valmut()
+            }
+            Some(current) => {
+                // SAFETY: We're not using this to mutate the tree.
+                unsafe { current.reborrow_mut() }
+                    .next_back_leaf_edge()
+                    .next_back_kv()
+                    .ok()?
+                    .into_kv_valmut()
+            }
+        };
+        Some((k, v))
+    }
+
+    /// Returns a read-only cursor pointing to the current element.
+    ///
+    /// The lifetime of the returned `Cursor` is bound to that of the
+    /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the
+    /// `CursorMut` is frozen for the lifetime of the `Cursor`.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn as_cursor(&self) -> Cursor<'_, K, V> {
+        Cursor {
+            // SAFETY: The tree is immutable while the cursor exists.
+            root: unsafe { self.root.reborrow_shared().as_ref() },
+            current: self.current.as_ref().map(|current| current.reborrow()),
+        }
+    }
+}
+
+// Now the tree editing operations
+impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
+    /// Inserts a new element into the `BTreeMap` after the current one.
+    ///
+    /// If the cursor is pointing at the "ghost" non-element then the new element is
+    /// inserted at the front of the `BTreeMap`.
+    ///
+    /// # Safety
+    ///
+    /// You must ensure that the `BTreeMap` invariants are maintained.
+    /// Specifically:
+    ///
+    /// * The key of the newly inserted element must be unique in the tree.
+    /// * All keys in the tree must remain in sorted order.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn insert_after_unchecked(&mut self, key: K, value: V) {
+        let edge = match self.current.take() {
+            None => {
+                // SAFETY: We have no other reference to the tree.
+                match unsafe { self.root.reborrow() } {
+                    root @ None => {
+                        // Tree is empty, allocate a new root.
+                        let mut node = NodeRef::new_leaf(self.alloc.clone());
+                        node.borrow_mut().push(key, value);
+                        *root = Some(node.forget_type());
+                        *self.length += 1;
+                        return;
+                    }
+                    Some(root) => root.borrow_mut().first_leaf_edge(),
+                }
+            }
+            Some(current) => current.next_leaf_edge(),
+        };
+
+        let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| {
+            drop(ins.left);
+            // SAFETY: The handle to the newly inserted value is always on a
+            // leaf node, so adding a new root node doesn't invalidate it.
+            let root = unsafe { self.root.reborrow().as_mut().unwrap() };
+            root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right)
+        });
+        self.current = handle.left_edge().next_back_kv().ok();
+        *self.length += 1;
+    }
+
+    /// Inserts a new element into the `BTreeMap` before the current one.
+    ///
+    /// If the cursor is pointing at the "ghost" non-element then the new element is
+    /// inserted at the end of the `BTreeMap`.
+    ///
+    /// # Safety
+    ///
+    /// You must ensure that the `BTreeMap` invariants are maintained.
+    /// Specifically:
+    ///
+    /// * The key of the newly inserted element must be unique in the tree.
+    /// * All keys in the tree must remain in sorted order.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn insert_before_unchecked(&mut self, key: K, value: V) {
+        let edge = match self.current.take() {
+            None => {
+                // SAFETY: We have no other reference to the tree.
+                match unsafe { self.root.reborrow() } {
+                    root @ None => {
+                        // Tree is empty, allocate a new root.
+                        let mut node = NodeRef::new_leaf(self.alloc.clone());
+                        node.borrow_mut().push(key, value);
+                        *root = Some(node.forget_type());
+                        *self.length += 1;
+                        return;
+                    }
+                    Some(root) => root.borrow_mut().last_leaf_edge(),
+                }
+            }
+            Some(current) => current.next_back_leaf_edge(),
+        };
+
+        let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| {
+            drop(ins.left);
+            // SAFETY: The handle to the newly inserted value is always on a
+            // leaf node, so adding a new root node doesn't invalidate it.
+            let root = unsafe { self.root.reborrow().as_mut().unwrap() };
+            root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right)
+        });
+        self.current = handle.right_edge().next_kv().ok();
+        *self.length += 1;
+    }
+
+    /// Inserts a new element into the `BTreeMap` after the current one.
+    ///
+    /// If the cursor is pointing at the "ghost" non-element then the new element is
+    /// inserted at the front of the `BTreeMap`.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if:
+    /// - the given key compares less than or equal to the current element (if
+    ///   any).
+    /// - the given key compares greater than or equal to the next element (if
+    ///   any).
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn insert_after(&mut self, key: K, value: V) {
+        if let Some(current) = self.key() {
+            if &key <= current {
+                panic!("key must be ordered above the current element");
+            }
+        }
+        if let Some((next, _)) = self.peek_prev() {
+            if &key >= next {
+                panic!("key must be ordered below the next element");
+            }
+        }
+        unsafe {
+            self.insert_after_unchecked(key, value);
+        }
+    }
+
+    /// Inserts a new element into the `BTreeMap` before the current one.
+    ///
+    /// If the cursor is pointing at the "ghost" non-element then the new element is
+    /// inserted at the end of the `BTreeMap`.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if:
+    /// - the given key compares greater than or equal to the current element
+    ///   (if any).
+    /// - the given key compares less than or equal to the previous element (if
+    ///   any).
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn insert_before(&mut self, key: K, value: V) {
+        if let Some(current) = self.key() {
+            if &key >= current {
+                panic!("key must be ordered below the current element");
+            }
+        }
+        if let Some((prev, _)) = self.peek_prev() {
+            if &key <= prev {
+                panic!("key must be ordered above the previous element");
+            }
+        }
+        unsafe {
+            self.insert_before_unchecked(key, value);
+        }
+    }
+
+    /// Removes the current element from the `BTreeMap`.
+    ///
+    /// The element that was removed is returned, and the cursor is
+    /// moved to point to the next element in the `BTreeMap`.
+    ///
+    /// If the cursor is currently pointing to the "ghost" non-element then no element
+    /// is removed and `None` is returned. The cursor is not moved in this case.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn remove_current(&mut self) -> Option<(K, V)> {
+        let current = self.current.take()?;
+        let mut emptied_internal_root = false;
+        let (kv, pos) =
+            current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone());
+        self.current = pos.next_kv().ok();
+        *self.length -= 1;
+        if emptied_internal_root {
+            // SAFETY: This is safe since current does not point within the now
+            // empty root node.
+            let root = unsafe { self.root.reborrow().as_mut().unwrap() };
+            root.pop_internal_level(self.alloc.clone());
+        }
+        Some(kv)
+    }
+
+    /// Removes the current element from the `BTreeMap`.
+    ///
+    /// The element that was removed is returned, and the cursor is
+    /// moved to point to the previous element in the `BTreeMap`.
+    ///
+    /// If the cursor is currently pointing to the "ghost" non-element then no element
+    /// is removed and `None` is returned. The cursor is not moved in this case.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn remove_current_and_move_back(&mut self) -> Option<(K, V)> {
+        let current = self.current.take()?;
+        let mut emptied_internal_root = false;
+        let (kv, pos) =
+            current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone());
+        self.current = pos.next_back_kv().ok();
+        *self.length -= 1;
+        if emptied_internal_root {
+            // SAFETY: This is safe since current does not point within the now
+            // empty root node.
+            let root = unsafe { self.root.reborrow().as_mut().unwrap() };
+            root.pop_internal_level(self.alloc.clone());
+        }
+        Some(kv)
+    }
 }
 
 #[cfg(test)]
index 370b58864af8f3f4f9d1d2c3af7bd054331f3c79..e9366eec9cec3028a05635b62672beed4602f5d3 100644 (file)
@@ -347,7 +347,7 @@ pub fn into_key(self) -> K {
     /// assert_eq!(map["poneyland"], 37);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn insert(self, value: V) -> &'a mut V {
+    pub fn insert(mut self, value: V) -> &'a mut V {
         let out_ptr = match self.handle {
             None => {
                 // SAFETY: There is no tree yet so no reference to it exists.
@@ -358,25 +358,27 @@ pub fn insert(self, value: V) -> &'a mut V {
                 map.length = 1;
                 val_ptr
             }
-            Some(handle) => match handle.insert_recursing(self.key, value, self.alloc.clone()) {
-                (None, val_ptr) => {
-                    // SAFETY: We have consumed self.handle.
-                    let map = unsafe { self.dormant_map.awaken() };
-                    map.length += 1;
-                    val_ptr
-                }
-                (Some(ins), val_ptr) => {
-                    drop(ins.left);
-                    // SAFETY: We have consumed self.handle and dropped the
-                    // remaining reference to the tree, ins.left.
-                    let map = unsafe { self.dormant_map.awaken() };
-                    let root = map.root.as_mut().unwrap(); // same as ins.left
-                    root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right);
-                    map.length += 1;
-                    val_ptr
-                }
-            },
+            Some(handle) => {
+                let new_handle =
+                    handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| {
+                        drop(ins.left);
+                        // SAFETY: Pushing a new root node doesn't invalidate
+                        // handles to existing nodes.
+                        let map = unsafe { self.dormant_map.reborrow() };
+                        let root = map.root.as_mut().unwrap(); // same as ins.left
+                        root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right)
+                    });
+
+                // Get the pointer to the value
+                let val_ptr = new_handle.into_val_mut();
+
+                // SAFETY: We have consumed self.handle.
+                let map = unsafe { self.dormant_map.awaken() };
+                map.length += 1;
+                val_ptr
+            }
         };
+
         // Now that we have finished growing the tree using borrowed references,
         // dereference the pointer to a part of it, that we picked up along the way.
         unsafe { &mut *out_ptr }
index 700b1463bfd51f961e8b7bb2cb43e991c9473d4e..76c2f27b46634a885a663a6ba53595a74f79702c 100644 (file)
@@ -2336,3 +2336,52 @@ fn from_array() {
     let unordered_duplicates = BTreeMap::from([(3, 4), (1, 2), (1, 2)]);
     assert_eq!(map, unordered_duplicates);
 }
+
+#[test]
+fn test_cursor() {
+    let map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
+
+    let mut cur = map.lower_bound(Bound::Unbounded);
+    assert_eq!(cur.key(), Some(&1));
+    cur.move_next();
+    assert_eq!(cur.key(), Some(&2));
+    assert_eq!(cur.peek_next(), Some((&3, &'c')));
+    cur.move_prev();
+    assert_eq!(cur.key(), Some(&1));
+    assert_eq!(cur.peek_prev(), None);
+
+    let mut cur = map.upper_bound(Bound::Excluded(&1));
+    assert_eq!(cur.key(), None);
+    cur.move_next();
+    assert_eq!(cur.key(), Some(&1));
+    cur.move_prev();
+    assert_eq!(cur.key(), None);
+    assert_eq!(cur.peek_prev(), Some((&3, &'c')));
+}
+
+#[test]
+fn test_cursor_mut() {
+    let mut map = BTreeMap::from([(1, 'a'), (3, 'c'), (5, 'e')]);
+    let mut cur = map.lower_bound_mut(Bound::Excluded(&3));
+    assert_eq!(cur.key(), Some(&5));
+    cur.insert_before(4, 'd');
+    assert_eq!(cur.key(), Some(&5));
+    assert_eq!(cur.peek_prev(), Some((&4, &mut 'd')));
+    cur.move_next();
+    assert_eq!(cur.key(), None);
+    cur.insert_before(6, 'f');
+    assert_eq!(cur.key(), None);
+    assert_eq!(cur.remove_current(), None);
+    assert_eq!(cur.key(), None);
+    cur.insert_after(0, '?');
+    assert_eq!(cur.key(), None);
+    assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f')]));
+
+    let mut cur = map.upper_bound_mut(Bound::Included(&5));
+    assert_eq!(cur.key(), Some(&5));
+    assert_eq!(cur.remove_current(), Some((5, 'e')));
+    assert_eq!(cur.key(), Some(&6));
+    assert_eq!(cur.remove_current_and_move_back(), Some((6, 'f')));
+    assert_eq!(cur.key(), Some(&4));
+    assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd')]));
+}
index 1e33c1e64d66e085a09cc51b86210556d92f4b11..b890717e50b2544b62dfbc73312ba9e975db3225 100644 (file)
@@ -4,6 +4,7 @@
 use core::ptr;
 
 use super::node::{marker, ForceResult::*, Handle, NodeRef};
+use super::search::SearchBound;
 
 use crate::alloc::Allocator;
 // `front` and `back` are always both `None` or both `Some`.
@@ -386,7 +387,7 @@ pub fn next_kv(
     /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV
     /// on the left side, which is either in the same leaf node or in an ancestor node.
     /// If the leaf edge is the first one in the tree, returns [`Result::Err`] with the root node.
-    fn next_back_kv(
+    pub fn next_back_kv(
         self,
     ) -> Result<
         Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>,
@@ -707,7 +708,9 @@ pub fn next_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, m
     }
 
     /// Returns the leaf edge closest to a KV for backward navigation.
-    fn next_back_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
+    pub fn next_back_leaf_edge(
+        self,
+    ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
         match self.force() {
             Leaf(leaf_kv) => leaf_kv.left_edge(),
             Internal(internal_kv) => {
@@ -717,3 +720,51 @@ fn next_back_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>,
         }
     }
 }
+
+impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
+    /// Returns the leaf edge corresponding to the first point at which the
+    /// given bound is true.
+    pub fn lower_bound<Q: ?Sized>(
+        self,
+        mut bound: SearchBound<&Q>,
+    ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>
+    where
+        Q: Ord,
+        K: Borrow<Q>,
+    {
+        let mut node = self;
+        loop {
+            let (edge, new_bound) = node.find_lower_bound_edge(bound);
+            match edge.force() {
+                Leaf(edge) => return edge,
+                Internal(edge) => {
+                    node = edge.descend();
+                    bound = new_bound;
+                }
+            }
+        }
+    }
+
+    /// Returns the leaf edge corresponding to the last point at which the
+    /// given bound is true.
+    pub fn upper_bound<Q: ?Sized>(
+        self,
+        mut bound: SearchBound<&Q>,
+    ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>
+    where
+        Q: Ord,
+        K: Borrow<Q>,
+    {
+        let mut node = self;
+        loop {
+            let (edge, new_bound) = node.find_upper_bound_edge(bound);
+            match edge.force() {
+                Leaf(edge) => return edge,
+                Internal(edge) => {
+                    node = edge.descend();
+                    bound = new_bound;
+                }
+            }
+        }
+    }
+}
index 6912466448fab444c6860425ba5970a41ef75a8b..3233a575ecf254e73fe18c3d55679716d276f96c 100644 (file)
@@ -442,6 +442,24 @@ fn into_leaf_mut(mut self) -> &'a mut LeafNode<K, V> {
         // SAFETY: we have exclusive access to the entire node.
         unsafe { &mut *ptr }
     }
+
+    /// Returns a dormant copy of this node with its lifetime erased which can
+    /// be reawakened later.
+    pub fn dormant(&self) -> NodeRef<marker::DormantMut, K, V, Type> {
+        NodeRef { height: self.height, node: self.node, _marker: PhantomData }
+    }
+}
+
+impl<K, V, Type> NodeRef<marker::DormantMut, K, V, Type> {
+    /// Revert to the unique borrow initially captured.
+    ///
+    /// # Safety
+    ///
+    /// The reborrow must have ended, i.e., the reference returned by `new` and
+    /// all pointers and references derived from it, must not be used anymore.
+    pub unsafe fn awaken<'a>(self) -> NodeRef<marker::Mut<'a>, K, V, Type> {
+        NodeRef { height: self.height, node: self.node, _marker: PhantomData }
+    }
 }
 
 impl<K, V, Type> NodeRef<marker::Dying, K, V, Type> {
@@ -798,6 +816,25 @@ pub unsafe fn reborrow_mut(
         // We can't use Handle::new_kv or Handle::new_edge because we don't know our type
         Handle { node: unsafe { self.node.reborrow_mut() }, idx: self.idx, _marker: PhantomData }
     }
+
+    /// Returns a dormant copy of this handle which can be reawakened later.
+    ///
+    /// See `DormantMutRef` for more details.
+    pub fn dormant(&self) -> Handle<NodeRef<marker::DormantMut, K, V, NodeType>, HandleType> {
+        Handle { node: self.node.dormant(), idx: self.idx, _marker: PhantomData }
+    }
+}
+
+impl<K, V, NodeType, HandleType> Handle<NodeRef<marker::DormantMut, K, V, NodeType>, HandleType> {
+    /// Revert to the unique borrow initially captured.
+    ///
+    /// # Safety
+    ///
+    /// The reborrow must have ended, i.e., the reference returned by `new` and
+    /// all pointers and references derived from it, must not be used anymore.
+    pub unsafe fn awaken<'a>(self) -> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, HandleType> {
+        Handle { node: unsafe { self.node.awaken() }, idx: self.idx, _marker: PhantomData }
+    }
 }
 
 impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, marker::Edge> {
@@ -851,9 +888,11 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
     /// Inserts a new key-value pair between the key-value pairs to the right and left of
     /// this edge. This method assumes that there is enough space in the node for the new
     /// pair to fit.
-    ///
-    /// The returned pointer points to the inserted value.
-    fn insert_fit(&mut self, key: K, val: V) -> *mut V {
+    unsafe fn insert_fit(
+        mut self,
+        key: K,
+        val: V,
+    ) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> {
         debug_assert!(self.node.len() < CAPACITY);
         let new_len = self.node.len() + 1;
 
@@ -862,7 +901,7 @@ fn insert_fit(&mut self, key: K, val: V) -> *mut V {
             slice_insert(self.node.val_area_mut(..new_len), self.idx, val);
             *self.node.len_mut() = new_len as u16;
 
-            self.node.val_area_mut(self.idx).assume_init_mut()
+            Handle::new_kv(self.node, self.idx)
         }
     }
 }
@@ -871,21 +910,26 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
     /// Inserts a new key-value pair between the key-value pairs to the right and left of
     /// this edge. This method splits the node if there isn't enough room.
     ///
-    /// The returned pointer points to the inserted value.
+    /// Returns a dormant handle to the inserted node which can be reawakened
+    /// once splitting is complete.
     fn insert<A: Allocator + Clone>(
-        mut self,
+        self,
         key: K,
         val: V,
         alloc: A,
-    ) -> (Option<SplitResult<'a, K, V, marker::Leaf>>, *mut V) {
+    ) -> (
+        Option<SplitResult<'a, K, V, marker::Leaf>>,
+        Handle<NodeRef<marker::DormantMut, K, V, marker::Leaf>, marker::KV>,
+    ) {
         if self.node.len() < CAPACITY {
-            let val_ptr = self.insert_fit(key, val);
-            (None, val_ptr)
+            // SAFETY: There is enough space in the node for insertion.
+            let handle = unsafe { self.insert_fit(key, val) };
+            (None, handle.dormant())
         } else {
             let (middle_kv_idx, insertion) = splitpoint(self.idx);
             let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
             let mut result = middle.split(alloc);
-            let mut insertion_edge = match insertion {
+            let insertion_edge = match insertion {
                 LeftOrRight::Left(insert_idx) => unsafe {
                     Handle::new_edge(result.left.reborrow_mut(), insert_idx)
                 },
@@ -893,8 +937,10 @@ fn insert<A: Allocator + Clone>(
                     Handle::new_edge(result.right.borrow_mut(), insert_idx)
                 },
             };
-            let val_ptr = insertion_edge.insert_fit(key, val);
-            (Some(result), val_ptr)
+            // SAFETY: We just split the node, so there is enough space for
+            // insertion.
+            let handle = unsafe { insertion_edge.insert_fit(key, val).dormant() };
+            (Some(result), handle)
         }
     }
 }
@@ -976,21 +1022,31 @@ pub fn insert_recursing<A: Allocator + Clone>(
         key: K,
         value: V,
         alloc: A,
-    ) -> (Option<SplitResult<'a, K, V, marker::LeafOrInternal>>, *mut V) {
-        let (mut split, val_ptr) = match self.insert(key, value, alloc.clone()) {
-            (None, val_ptr) => return (None, val_ptr),
-            (Some(split), val_ptr) => (split.forget_node_type(), val_ptr),
+        split_root: impl FnOnce(SplitResult<'a, K, V, marker::LeafOrInternal>),
+    ) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> {
+        let (mut split, handle) = match self.insert(key, value, alloc.clone()) {
+            // SAFETY: we have finished splitting and can now re-awaken the
+            // handle to the inserted element.
+            (None, handle) => return unsafe { handle.awaken() },
+            (Some(split), handle) => (split.forget_node_type(), handle),
         };
 
         loop {
             split = match split.left.ascend() {
                 Ok(parent) => {
                     match parent.insert(split.kv.0, split.kv.1, split.right, alloc.clone()) {
-                        None => return (None, val_ptr),
+                        // SAFETY: we have finished splitting and can now re-awaken the
+                        // handle to the inserted element.
+                        None => return unsafe { handle.awaken() },
                         Some(split) => split.forget_node_type(),
                     }
                 }
-                Err(root) => return (Some(SplitResult { left: root, ..split }), val_ptr),
+                Err(root) => {
+                    split_root(SplitResult { left: root, ..split });
+                    // SAFETY: we have finished splitting and can now re-awaken the
+                    // handle to the inserted element.
+                    return unsafe { handle.awaken() };
+                }
             };
         }
     }
@@ -1043,6 +1099,14 @@ pub fn into_val_mut(self) -> &'a mut V {
         let leaf = self.node.into_leaf_mut();
         unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }
     }
+
+    pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) {
+        debug_assert!(self.idx < self.node.len());
+        let leaf = self.node.into_leaf_mut();
+        let k = unsafe { leaf.keys.get_unchecked(self.idx).assume_init_ref() };
+        let v = unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() };
+        (k, v)
+    }
 }
 
 impl<'a, K, V, NodeType> Handle<NodeRef<marker::ValMut<'a>, K, V, NodeType>, marker::KV> {
@@ -1667,6 +1731,7 @@ pub enum LeafOrInternal {}
 
     pub enum Owned {}
     pub enum Dying {}
+    pub enum DormantMut {}
     pub struct Immut<'a>(PhantomData<&'a ()>);
     pub struct Mut<'a>(PhantomData<&'a mut ()>);
     pub struct ValMut<'a>(PhantomData<&'a mut ()>);
@@ -1688,6 +1753,7 @@ impl BorrowType for Dying {}
     impl<'a> BorrowType for Immut<'a> {}
     impl<'a> BorrowType for Mut<'a> {}
     impl<'a> BorrowType for ValMut<'a> {}
+    impl BorrowType for DormantMut {}
 
     pub enum KV {}
     pub enum Edge {}
index ca182c8109ec97d3f1ad5dc01353a342e656d0f2..7565918851554bd5de13ae1f88ba4ef551fd3119 100644 (file)
@@ -928,12 +928,12 @@ pub fn push_str(&mut self, string: &str) {
 
     /// Copies elements from `src` range to the end of the string.
     ///
-    /// ## Panics
+    /// # Panics
     ///
     /// Panics if the starting point or end point do not lie on a [`char`]
     /// boundary, or if they're out of bounds.
     ///
-    /// ## Examples
+    /// # Examples
     ///
     /// ```
     /// #![feature(string_extend_from_within)]
index 9408f83c32f7cd368f9b685bdac3a3fa471e5751..5d4df1ac8bd5883b5539539f7f11db2316d84a50 100644 (file)
@@ -1,26 +1,26 @@
-use test::Bencher;
+use test::{black_box, Bencher};
 
 const CHARS: [char; 9] = ['0', 'x', '2', '5', 'A', 'f', '7', '8', '9'];
 const RADIX: [u32; 5] = [2, 8, 10, 16, 32];
 
 #[bench]
 fn bench_to_digit_radix_2(b: &mut Bencher) {
-    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(2)).min())
+    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_digit(2)).min())
 }
 
 #[bench]
 fn bench_to_digit_radix_10(b: &mut Bencher) {
-    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(10)).min())
+    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_digit(10)).min())
 }
 
 #[bench]
 fn bench_to_digit_radix_16(b: &mut Bencher) {
-    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(16)).min())
+    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_digit(16)).min())
 }
 
 #[bench]
 fn bench_to_digit_radix_36(b: &mut Bencher) {
-    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(36)).min())
+    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_digit(36)).min())
 }
 
 #[bench]
@@ -31,47 +31,59 @@ fn bench_to_digit_radix_var(b: &mut Bencher) {
             .cycle()
             .zip(RADIX.iter().cycle())
             .take(10_000)
-            .map(|(c, radix)| c.to_digit(*radix))
+            .map(|(c, radix)| black_box(c).to_digit(*radix))
             .min()
     })
 }
 
 #[bench]
 fn bench_to_ascii_uppercase(b: &mut Bencher) {
-    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_uppercase()).min())
+    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_ascii_uppercase()).min())
 }
 
 #[bench]
 fn bench_to_ascii_lowercase(b: &mut Bencher) {
-    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_lowercase()).min())
+    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_ascii_lowercase()).min())
 }
 
 #[bench]
 fn bench_ascii_mix_to_uppercase(b: &mut Bencher) {
-    b.iter(|| (0..=255).cycle().take(10_000).map(|b| char::from(b).to_uppercase()).count())
+    b.iter(|| {
+        (0..=255).cycle().take(10_000).map(|b| black_box(char::from(b)).to_uppercase()).count()
+    })
 }
 
 #[bench]
 fn bench_ascii_mix_to_lowercase(b: &mut Bencher) {
-    b.iter(|| (0..=255).cycle().take(10_000).map(|b| char::from(b).to_lowercase()).count())
+    b.iter(|| {
+        (0..=255).cycle().take(10_000).map(|b| black_box(char::from(b)).to_lowercase()).count()
+    })
 }
 
 #[bench]
 fn bench_ascii_char_to_uppercase(b: &mut Bencher) {
-    b.iter(|| (0..=127).cycle().take(10_000).map(|b| char::from(b).to_uppercase()).count())
+    b.iter(|| {
+        (0..=127).cycle().take(10_000).map(|b| black_box(char::from(b)).to_uppercase()).count()
+    })
 }
 
 #[bench]
 fn bench_ascii_char_to_lowercase(b: &mut Bencher) {
-    b.iter(|| (0..=127).cycle().take(10_000).map(|b| char::from(b).to_lowercase()).count())
+    b.iter(|| {
+        (0..=127).cycle().take(10_000).map(|b| black_box(char::from(b)).to_lowercase()).count()
+    })
 }
 
 #[bench]
 fn bench_non_ascii_char_to_uppercase(b: &mut Bencher) {
-    b.iter(|| (128..=255).cycle().take(10_000).map(|b| char::from(b).to_uppercase()).count())
+    b.iter(|| {
+        (128..=255).cycle().take(10_000).map(|b| black_box(char::from(b)).to_uppercase()).count()
+    })
 }
 
 #[bench]
 fn bench_non_ascii_char_to_lowercase(b: &mut Bencher) {
-    b.iter(|| (128..=255).cycle().take(10_000).map(|b| char::from(b).to_lowercase()).count())
+    b.iter(|| {
+        (128..=255).cycle().take(10_000).map(|b| black_box(char::from(b)).to_lowercase()).count()
+    })
 }
index 319b9773e49fee6042cbcb8cd67d82ed80b268bb..377c99effd03c7b0f58435f4013aa88ce46470af 100644 (file)
@@ -1,14 +1,14 @@
 use super::super::*;
 use core::num::flt2dec::strategy::dragon::*;
 use std::mem::MaybeUninit;
-use test::Bencher;
+use test::{black_box, Bencher};
 
 #[bench]
 fn bench_small_shortest(b: &mut Bencher) {
     let decoded = decode_finite(3.141592f64);
     let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS];
     b.iter(|| {
-        format_shortest(&decoded, &mut buf);
+        format_shortest(black_box(&decoded), &mut buf);
     });
 }
 
@@ -17,7 +17,7 @@ fn bench_big_shortest(b: &mut Bencher) {
     let decoded = decode_finite(f64::MAX);
     let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS];
     b.iter(|| {
-        format_shortest(&decoded, &mut buf);
+        format_shortest(black_box(&decoded), &mut buf);
     });
 }
 
@@ -26,7 +26,7 @@ fn bench_small_exact_3(b: &mut Bencher) {
     let decoded = decode_finite(3.141592f64);
     let mut buf = [MaybeUninit::new(0); 3];
     b.iter(|| {
-        format_exact(&decoded, &mut buf, i16::MIN);
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
 
@@ -35,7 +35,7 @@ fn bench_big_exact_3(b: &mut Bencher) {
     let decoded = decode_finite(f64::MAX);
     let mut buf = [MaybeUninit::new(0); 3];
     b.iter(|| {
-        format_exact(&decoded, &mut buf, i16::MIN);
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
 
@@ -44,7 +44,7 @@ fn bench_small_exact_12(b: &mut Bencher) {
     let decoded = decode_finite(3.141592f64);
     let mut buf = [MaybeUninit::new(0); 12];
     b.iter(|| {
-        format_exact(&decoded, &mut buf, i16::MIN);
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
 
@@ -53,7 +53,7 @@ fn bench_big_exact_12(b: &mut Bencher) {
     let decoded = decode_finite(f64::MAX);
     let mut buf = [MaybeUninit::new(0); 12];
     b.iter(|| {
-        format_exact(&decoded, &mut buf, i16::MIN);
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
 
@@ -62,7 +62,7 @@ fn bench_small_exact_inf(b: &mut Bencher) {
     let decoded = decode_finite(3.141592f64);
     let mut buf = [MaybeUninit::new(0); 1024];
     b.iter(|| {
-        format_exact(&decoded, &mut buf, i16::MIN);
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
 
@@ -71,6 +71,6 @@ fn bench_big_exact_inf(b: &mut Bencher) {
     let decoded = decode_finite(f64::MAX);
     let mut buf = [MaybeUninit::new(0); 1024];
     b.iter(|| {
-        format_exact(&decoded, &mut buf, i16::MIN);
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
index 8e47a046cdea5fc330308a9f91160c4d57dd820b..6bea5e55d37bbc1bafad53c1ac0c98a4eafe5d15 100644 (file)
@@ -1,7 +1,7 @@
 use super::super::*;
 use core::num::flt2dec::strategy::grisu::*;
 use std::mem::MaybeUninit;
-use test::Bencher;
+use test::{black_box, Bencher};
 
 pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
     match decode(v).1 {
@@ -15,7 +15,7 @@ fn bench_small_shortest(b: &mut Bencher) {
     let decoded = decode_finite(3.141592f64);
     let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS];
     b.iter(|| {
-        format_shortest(&decoded, &mut buf);
+        format_shortest(black_box(&decoded), &mut buf);
     });
 }
 
@@ -24,7 +24,7 @@ fn bench_big_shortest(b: &mut Bencher) {
     let decoded = decode_finite(f64::MAX);
     let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS];
     b.iter(|| {
-        format_shortest(&decoded, &mut buf);
+        format_shortest(black_box(&decoded), &mut buf);
     });
 }
 
@@ -33,7 +33,7 @@ fn bench_small_exact_3(b: &mut Bencher) {
     let decoded = decode_finite(3.141592f64);
     let mut buf = [MaybeUninit::new(0); 3];
     b.iter(|| {
-        format_exact(&decoded, &mut buf, i16::MIN);
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
 
@@ -42,7 +42,7 @@ fn bench_big_exact_3(b: &mut Bencher) {
     let decoded = decode_finite(f64::MAX);
     let mut buf = [MaybeUninit::new(0); 3];
     b.iter(|| {
-        format_exact(&decoded, &mut buf, i16::MIN);
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
 
@@ -51,7 +51,7 @@ fn bench_small_exact_12(b: &mut Bencher) {
     let decoded = decode_finite(3.141592f64);
     let mut buf = [MaybeUninit::new(0); 12];
     b.iter(|| {
-        format_exact(&decoded, &mut buf, i16::MIN);
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
 
@@ -60,7 +60,7 @@ fn bench_big_exact_12(b: &mut Bencher) {
     let decoded = decode_finite(f64::MAX);
     let mut buf = [MaybeUninit::new(0); 12];
     b.iter(|| {
-        format_exact(&decoded, &mut buf, i16::MIN);
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
 
@@ -69,7 +69,7 @@ fn bench_small_exact_inf(b: &mut Bencher) {
     let decoded = decode_finite(3.141592f64);
     let mut buf = [MaybeUninit::new(0); 1024];
     b.iter(|| {
-        format_exact(&decoded, &mut buf, i16::MIN);
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
 
@@ -78,6 +78,6 @@ fn bench_big_exact_inf(b: &mut Bencher) {
     let decoded = decode_finite(f64::MAX);
     let mut buf = [MaybeUninit::new(0); 1024];
     b.iter(|| {
-        format_exact(&decoded, &mut buf, i16::MIN);
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
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 74055602ec2e62df6c58148f0725789d61faaf02..e11bca5962a156a9059d7a8ceb561731fe68ee53 100644 (file)
@@ -872,13 +872,14 @@ pub trait Destruct {}
 pub trait Tuple {}
 
 /// A marker for things
-#[unstable(feature = "pointer_sized_trait", issue = "none")]
-#[lang = "pointer_sized"]
+#[unstable(feature = "pointer_like_trait", issue = "none")]
+#[cfg_attr(bootstrap, lang = "pointer_sized")]
+#[cfg_attr(not(bootstrap), lang = "pointer_like")]
 #[rustc_on_unimplemented(
-    message = "`{Self}` needs to be a pointer-sized type",
-    label = "`{Self}` needs to be a pointer-sized type"
+    message = "`{Self}` needs to have the same alignment and size as a pointer",
+    label = "`{Self}` needs to be a pointer-like type"
 )]
-pub trait PointerSized {}
+pub trait PointerLike {}
 
 /// Implementations of `Copy` for primitive types.
 ///
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 75c52d3ecfc8bd56d7350362d90c5dff4e58ea55..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;
 }
@@ -545,7 +549,7 @@ fn div(self, other: $t) -> $t { self / other }
 #[lang = "rem"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
-    message = "cannot mod `{Self}` by `{Rhs}`",
+    message = "cannot calculate the remainder of `{Self}` divided by `{Rhs}`",
     label = "no implementation for `{Self} % {Rhs}`"
 )]
 #[doc(alias = "%")]
@@ -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;
 }
@@ -981,7 +987,7 @@ fn div_assign(&mut self, other: $t) { *self /= other }
 #[lang = "rem_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
 #[rustc_on_unimplemented(
-    message = "cannot mod-assign `{Self}` by `{Rhs}``",
+    message = "cannot calculate and assign the remainder of `{Self}` divided by `{Rhs}`",
     label = "no implementation for `{Self} %= {Rhs}`"
 )]
 #[doc(alias = "%")]
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 d93a3a57ecd27fdcdb94a4aa479a5e8ceb02be3c..6ea16bf643071120f523a21f7cf88d3710ceb639 100644 (file)
@@ -805,8 +805,9 @@ pub fn iter_mut(&mut self) -> IterMut<'_, T> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[track_caller]
     pub fn windows(&self, size: usize) -> Windows<'_, T> {
-        let size = NonZeroUsize::new(size).expect("size is zero");
+        let size = NonZeroUsize::new(size).expect("window size must be non-zero");
         Windows::new(self, size)
     }
 
@@ -839,8 +840,9 @@ pub fn windows(&self, size: usize) -> Windows<'_, T> {
     /// [`rchunks`]: slice::rchunks
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[track_caller]
     pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> {
-        assert_ne!(chunk_size, 0, "chunks cannot have a size of zero");
+        assert!(chunk_size != 0, "chunk size must be non-zero");
         Chunks::new(self, chunk_size)
     }
 
@@ -877,8 +879,9 @@ pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> {
     /// [`rchunks_mut`]: slice::rchunks_mut
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[track_caller]
     pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> {
-        assert_ne!(chunk_size, 0, "chunks cannot have a size of zero");
+        assert!(chunk_size != 0, "chunk size must be non-zero");
         ChunksMut::new(self, chunk_size)
     }
 
@@ -914,8 +917,9 @@ pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> {
     /// [`rchunks_exact`]: slice::rchunks_exact
     #[stable(feature = "chunks_exact", since = "1.31.0")]
     #[inline]
+    #[track_caller]
     pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> {
-        assert_ne!(chunk_size, 0, "chunks cannot have a size of zero");
+        assert!(chunk_size != 0, "chunk size must be non-zero");
         ChunksExact::new(self, chunk_size)
     }
 
@@ -956,8 +960,9 @@ pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> {
     /// [`rchunks_exact_mut`]: slice::rchunks_exact_mut
     #[stable(feature = "chunks_exact", since = "1.31.0")]
     #[inline]
+    #[track_caller]
     pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> {
-        assert_ne!(chunk_size, 0, "chunks cannot have a size of zero");
+        assert!(chunk_size != 0, "chunk size must be non-zero");
         ChunksExactMut::new(self, chunk_size)
     }
 
@@ -1037,9 +1042,10 @@ pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> {
     /// ```
     #[unstable(feature = "slice_as_chunks", issue = "74985")]
     #[inline]
+    #[track_caller]
     #[must_use]
     pub fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T]) {
-        assert_ne!(N, 0, "chunks cannot have a size of zero");
+        assert!(N != 0, "chunk size must be non-zero");
         let len = self.len() / N;
         let (multiple_of_n, remainder) = self.split_at(len * N);
         // SAFETY: We already panicked for zero, and ensured by construction
@@ -1068,9 +1074,10 @@ pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> {
     /// ```
     #[unstable(feature = "slice_as_chunks", issue = "74985")]
     #[inline]
+    #[track_caller]
     #[must_use]
     pub fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]]) {
-        assert_ne!(N, 0, "chunks cannot have a size of zero");
+        assert!(N != 0, "chunk size must be non-zero");
         let len = self.len() / N;
         let (remainder, multiple_of_n) = self.split_at(self.len() - len * N);
         // SAFETY: We already panicked for zero, and ensured by construction
@@ -1108,8 +1115,9 @@ pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> {
     /// [`chunks_exact`]: slice::chunks_exact
     #[unstable(feature = "array_chunks", issue = "74985")]
     #[inline]
+    #[track_caller]
     pub fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
-        assert_ne!(N, 0, "chunks cannot have a size of zero");
+        assert!(N != 0, "chunk size must be non-zero");
         ArrayChunks::new(self)
     }
 
@@ -1186,9 +1194,10 @@ pub fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
     /// ```
     #[unstable(feature = "slice_as_chunks", issue = "74985")]
     #[inline]
+    #[track_caller]
     #[must_use]
     pub fn as_chunks_mut<const N: usize>(&mut self) -> (&mut [[T; N]], &mut [T]) {
-        assert_ne!(N, 0, "chunks cannot have a size of zero");
+        assert!(N != 0, "chunk size must be non-zero");
         let len = self.len() / N;
         let (multiple_of_n, remainder) = self.split_at_mut(len * N);
         // SAFETY: We already panicked for zero, and ensured by construction
@@ -1223,9 +1232,10 @@ pub fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
     /// ```
     #[unstable(feature = "slice_as_chunks", issue = "74985")]
     #[inline]
+    #[track_caller]
     #[must_use]
     pub fn as_rchunks_mut<const N: usize>(&mut self) -> (&mut [T], &mut [[T; N]]) {
-        assert_ne!(N, 0, "chunks cannot have a size of zero");
+        assert!(N != 0, "chunk size must be non-zero");
         let len = self.len() / N;
         let (remainder, multiple_of_n) = self.split_at_mut(self.len() - len * N);
         // SAFETY: We already panicked for zero, and ensured by construction
@@ -1265,8 +1275,9 @@ pub fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
     /// [`chunks_exact_mut`]: slice::chunks_exact_mut
     #[unstable(feature = "array_chunks", issue = "74985")]
     #[inline]
+    #[track_caller]
     pub fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N> {
-        assert_ne!(N, 0, "chunks cannot have a size of zero");
+        assert!(N != 0, "chunk size must be non-zero");
         ArrayChunksMut::new(self)
     }
 
@@ -1297,8 +1308,9 @@ pub fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N> {
     /// [`windows`]: slice::windows
     #[unstable(feature = "array_windows", issue = "75027")]
     #[inline]
+    #[track_caller]
     pub fn array_windows<const N: usize>(&self) -> ArrayWindows<'_, T, N> {
-        assert_ne!(N, 0, "windows cannot have a size of zero");
+        assert!(N != 0, "window size must be non-zero");
         ArrayWindows::new(self)
     }
 
@@ -1331,8 +1343,9 @@ pub fn array_windows<const N: usize>(&self) -> ArrayWindows<'_, T, N> {
     /// [`chunks`]: slice::chunks
     #[stable(feature = "rchunks", since = "1.31.0")]
     #[inline]
+    #[track_caller]
     pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> {
-        assert!(chunk_size != 0);
+        assert!(chunk_size != 0, "chunk size must be non-zero");
         RChunks::new(self, chunk_size)
     }
 
@@ -1369,8 +1382,9 @@ pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> {
     /// [`chunks_mut`]: slice::chunks_mut
     #[stable(feature = "rchunks", since = "1.31.0")]
     #[inline]
+    #[track_caller]
     pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> {
-        assert!(chunk_size != 0);
+        assert!(chunk_size != 0, "chunk size must be non-zero");
         RChunksMut::new(self, chunk_size)
     }
 
@@ -1408,8 +1422,9 @@ pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> {
     /// [`chunks_exact`]: slice::chunks_exact
     #[stable(feature = "rchunks", since = "1.31.0")]
     #[inline]
+    #[track_caller]
     pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> {
-        assert!(chunk_size != 0);
+        assert!(chunk_size != 0, "chunk size must be non-zero");
         RChunksExact::new(self, chunk_size)
     }
 
@@ -1451,8 +1466,9 @@ pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> {
     /// [`chunks_exact_mut`]: slice::chunks_exact_mut
     #[stable(feature = "rchunks", since = "1.31.0")]
     #[inline]
+    #[track_caller]
     pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> {
-        assert!(chunk_size != 0);
+        assert!(chunk_size != 0, "chunk size must be non-zero");
         RChunksExactMut::new(self, chunk_size)
     }
 
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..7f07e4fddef77ca7f0c0e51f5352a922b5d5b776 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 = "107792")]
+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..b2b6d86134b6292bff70b20964bd26584b1bcac8 100644 (file)
 
 #[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
 pub use self::buffered::WriterPanicked;
+#[unstable(feature = "raw_os_error_ty", issue = "107792")]
+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 c41e093a7e5c6442f7022cd09d7f587f680af185..439b8d52a2d8673b62486a2c75da854f65ef2386 100644 (file)
@@ -396,6 +396,14 @@ fn as_fd(&self) -> BorrowedFd<'_> {
     }
 }
 
+#[stable(feature = "asfd_rc", since = "CURRENT_RUSTC_VERSION")]
+impl<T: AsFd> AsFd for crate::rc::Rc<T> {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        (**self).as_fd()
+    }
+}
+
 #[stable(feature = "asfd_ptrs", since = "1.64.0")]
 impl<T: AsFd> AsFd for Box<T> {
     #[inline]
index f92a05066706d276cb98599992d518e37ee4b6a4..c138162f1ab08b5cad949162ec687a9eb1ea4467 100644 (file)
@@ -244,6 +244,14 @@ fn as_raw_fd(&self) -> RawFd {
     }
 }
 
+#[stable(feature = "asfd_rc", since = "CURRENT_RUSTC_VERSION")]
+impl<T: AsRawFd> AsRawFd for crate::rc::Rc<T> {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        (**self).as_raw_fd()
+    }
+}
+
 #[stable(feature = "asrawfd_ptrs", since = "1.63.0")]
 impl<T: AsRawFd> AsRawFd for Box<T> {
     #[inline]
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 abdd12127d36659fdcd30e333deedb3a465a36e6..5b19a658fb5432c0d4983860fd449f19313ac2d3 100644 (file)
@@ -2,7 +2,6 @@ from __future__ import absolute_import, division, print_function
 import argparse
 import contextlib
 import datetime
-import distutils.version
 import hashlib
 import json
 import os
@@ -13,17 +12,17 @@ import sys
 import tarfile
 import tempfile
 
-from time import time, sleep
+from time import time
 
-def support_xz():
-    try:
-        with tempfile.NamedTemporaryFile(delete=False) as temp_file:
-            temp_path = temp_file.name
-        with tarfile.open(temp_path, "w:xz"):
-            pass
-        return True
-    except tarfile.CompressionError:
-        return False
+try:
+    import lzma
+except ImportError:
+    lzma = None
+
+if sys.platform == 'win32':
+    EXE_SUFFIX = ".exe"
+else:
+    EXE_SUFFIX = ""
 
 def get(base, url, path, checksums, verbose=False):
     with tempfile.NamedTemporaryFile(delete=False) as temp_file:
@@ -61,7 +60,7 @@ def get(base, url, path, checksums, verbose=False):
 
 
 def download(path, url, probably_big, verbose):
-    for _ in range(0, 4):
+    for _ in range(4):
         try:
             _download(path, url, probably_big, verbose, True)
             return
@@ -395,17 +394,18 @@ class RustBuild(object):
     def __init__(self):
         self.checksums_sha256 = {}
         self.stage0_compiler = None
-        self._download_url = ''
+        self.download_url = ''
         self.build = ''
         self.build_dir = ''
         self.clean = False
         self.config_toml = ''
         self.rust_root = ''
-        self.use_locked_deps = ''
-        self.use_vendored_sources = ''
+        self.use_locked_deps = False
+        self.use_vendored_sources = False
         self.verbose = False
         self.git_version = None
         self.nix_deps_dir = None
+        self._should_fix_bins_and_dylibs = None
 
     def download_toolchain(self):
         """Fetch the build system for Rust, written in Rust
@@ -426,7 +426,7 @@ class RustBuild(object):
                  self.program_out_of_date(self.rustc_stamp(), key)):
             if os.path.exists(bin_root):
                 shutil.rmtree(bin_root)
-            tarball_suffix = '.tar.xz' if support_xz() else '.tar.gz'
+            tarball_suffix = '.tar.gz' if lzma is None else '.tar.xz'
             filename = "rust-std-{}-{}{}".format(
                 rustc_channel, self.build, tarball_suffix)
             pattern = "rust-std-{}".format(self.build)
@@ -437,15 +437,17 @@ class RustBuild(object):
             filename = "cargo-{}-{}{}".format(rustc_channel, self.build,
                                             tarball_suffix)
             self._download_component_helper(filename, "cargo", tarball_suffix)
-            self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root))
-
-            self.fix_bin_or_dylib("{}/bin/rustc".format(bin_root))
-            self.fix_bin_or_dylib("{}/bin/rustdoc".format(bin_root))
-            self.fix_bin_or_dylib("{}/libexec/rust-analyzer-proc-macro-srv".format(bin_root))
-            lib_dir = "{}/lib".format(bin_root)
-            for lib in os.listdir(lib_dir):
-                if lib.endswith(".so"):
-                    self.fix_bin_or_dylib(os.path.join(lib_dir, lib))
+            if self.should_fix_bins_and_dylibs():
+                self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root))
+
+                self.fix_bin_or_dylib("{}/bin/rustc".format(bin_root))
+                self.fix_bin_or_dylib("{}/bin/rustdoc".format(bin_root))
+                self.fix_bin_or_dylib("{}/libexec/rust-analyzer-proc-macro-srv".format(bin_root))
+                lib_dir = "{}/lib".format(bin_root)
+                for lib in os.listdir(lib_dir):
+                    if lib.endswith(".so"):
+                        self.fix_bin_or_dylib(os.path.join(lib_dir, lib))
+
             with output(self.rustc_stamp()) as rust_stamp:
                 rust_stamp.write(key)
 
@@ -458,60 +460,73 @@ class RustBuild(object):
         if not os.path.exists(rustc_cache):
             os.makedirs(rustc_cache)
 
-        base = self._download_url
-        url = "dist/{}".format(key)
         tarball = os.path.join(rustc_cache, filename)
         if not os.path.exists(tarball):
             get(
-                base,
-                "{}/{}".format(url, filename),
+                self.download_url,
+                "dist/{}/{}".format(key, filename),
                 tarball,
                 self.checksums_sha256,
                 verbose=self.verbose,
             )
         unpack(tarball, tarball_suffix, self.bin_root(), match=pattern, verbose=self.verbose)
 
-    def fix_bin_or_dylib(self, fname):
-        """Modifies the interpreter section of 'fname' to fix the dynamic linker,
-        or the RPATH section, to fix the dynamic library search path
-
-        This method is only required on NixOS and uses the PatchELF utility to
-        change the interpreter/RPATH of ELF executables.
-
-        Please see https://nixos.org/patchelf.html for more information
+    def should_fix_bins_and_dylibs(self):
+        """Whether or not `fix_bin_or_dylib` needs to be run; can only be True
+        on NixOS.
         """
-        default_encoding = sys.getdefaultencoding()
-        try:
-            ostype = subprocess.check_output(
-                ['uname', '-s']).strip().decode(default_encoding)
-        except subprocess.CalledProcessError:
-            return
-        except OSError as reason:
-            if getattr(reason, 'winerror', None) is not None:
-                return
-            raise reason
+        if self._should_fix_bins_and_dylibs is not None:
+            return self._should_fix_bins_and_dylibs
 
-        if ostype != "Linux":
-            return
+        def get_answer():
+            default_encoding = sys.getdefaultencoding()
+            try:
+                ostype = subprocess.check_output(
+                    ['uname', '-s']).strip().decode(default_encoding)
+            except subprocess.CalledProcessError:
+                return False
+            except OSError as reason:
+                if getattr(reason, 'winerror', None) is not None:
+                    return False
+                raise reason
+
+            if ostype != "Linux":
+                return False
+
+            # If the user has asked binaries to be patched for Nix, then
+            # don't check for NixOS or `/lib`.
+            if self.get_toml("patch-binaries-for-nix", "build") == "true":
+                return True
 
-        # If the user has asked binaries to be patched for Nix, then
-        # don't check for NixOS or `/lib`, just continue to the patching.
-        if self.get_toml('patch-binaries-for-nix', 'build') != 'true':
             # Use `/etc/os-release` instead of `/etc/NIXOS`.
             # The latter one does not exist on NixOS when using tmpfs as root.
             try:
                 with open("/etc/os-release", "r") as f:
-                    if not any(l.strip() in ["ID=nixos", "ID='nixos'", 'ID="nixos"'] for l in f):
-                        return
+                    if not any(l.strip() in ("ID=nixos", "ID='nixos'", 'ID="nixos"') for l in f):
+                        return False
             except FileNotFoundError:
-                return
+                return False
             if os.path.exists("/lib"):
-                return
+                return False
+
+            return True
+
+        answer = self._should_fix_bins_and_dylibs = get_answer()
+        if answer:
+            print("info: You seem to be using Nix.")
+        return answer
+
+    def fix_bin_or_dylib(self, fname):
+        """Modifies the interpreter section of 'fname' to fix the dynamic linker,
+        or the RPATH section, to fix the dynamic library search path
 
-        # At this point we're pretty sure the user is running NixOS or
-        # using Nix
-        nix_os_msg = "info: you seem to be using Nix. Attempting to patch"
-        print(nix_os_msg, fname)
+        This method is only required on NixOS and uses the PatchELF utility to
+        change the interpreter/RPATH of ELF executables.
+
+        Please see https://nixos.org/patchelf.html for more information
+        """
+        assert self._should_fix_bins_and_dylibs is True
+        print("attempting to patch", fname)
 
         # Only build `.nix-deps` once.
         nix_deps_dir = self.nix_deps_dir
@@ -666,8 +681,7 @@ class RustBuild(object):
         config = self.get_toml(program)
         if config:
             return os.path.expanduser(config)
-        return os.path.join(self.bin_root(), "bin", "{}{}".format(
-            program, self.exe_suffix()))
+        return os.path.join(self.bin_root(), "bin", "{}{}".format(program, EXE_SUFFIX))
 
     @staticmethod
     def get_string(line):
@@ -692,13 +706,6 @@ class RustBuild(object):
             return line[start + 1:end]
         return None
 
-    @staticmethod
-    def exe_suffix():
-        """Return a suffix for executables"""
-        if sys.platform == 'win32':
-            return '.exe'
-        return ''
-
     def bootstrap_binary(self):
         """Return the path of the bootstrap binary
 
@@ -710,7 +717,7 @@ class RustBuild(object):
         """
         return os.path.join(self.build_dir, "bootstrap", "debug", "bootstrap")
 
-    def build_bootstrap(self, color):
+    def build_bootstrap(self, color, verbose_count):
         """Build bootstrap"""
         print("Building bootstrap")
         build_dir = os.path.join(self.build_dir, "bootstrap")
@@ -757,7 +764,6 @@ class RustBuild(object):
         if target_linker is not None:
             env["RUSTFLAGS"] += " -C linker=" + target_linker
         env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes"
-        env["RUSTFLAGS"] += " -Wsemicolon_in_expressions_from_macros"
         if self.get_toml("deny-warnings", "rust") != "false":
             env["RUSTFLAGS"] += " -Dwarnings"
 
@@ -768,8 +774,7 @@ class RustBuild(object):
                 self.cargo()))
         args = [self.cargo(), "build", "--manifest-path",
                 os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")]
-        for _ in range(0, self.verbose):
-            args.append("--verbose")
+        args.extend("--verbose" for _ in range(verbose_count))
         if self.use_locked_deps:
             args.append("--locked")
         if self.use_vendored_sources:
@@ -792,16 +797,7 @@ class RustBuild(object):
         so use `self.build` where possible.
         """
         config = self.get_toml('build')
-        if config:
-            return config
-        return default_build_triple(self.verbose)
-
-    def set_dist_environment(self, url):
-        """Set download URL for normal environment"""
-        if 'RUSTUP_DIST_SERVER' in os.environ:
-            self._download_url = os.environ['RUSTUP_DIST_SERVER']
-        else:
-            self._download_url = url
+        return config or default_build_triple(self.verbose)
 
     def check_vendored_status(self):
         """Check that vendoring is configured properly"""
@@ -834,17 +830,10 @@ class RustBuild(object):
             if os.path.exists(cargo_dir):
                 shutil.rmtree(cargo_dir)
 
-def bootstrap(help_triggered):
-    """Configure, fetch, build and run the initial bootstrap"""
-
-    # If the user is asking for help, let them know that the whole download-and-build
-    # process has to happen before anything is printed out.
-    if help_triggered:
-        print("info: Downloading and building bootstrap before processing --help")
-        print("      command. See src/bootstrap/README.md for help with common")
-        print("      commands.")
-
-    parser = argparse.ArgumentParser(description='Build rust')
+def parse_args():
+    """Parse the command line arguments that the python script needs."""
+    parser = argparse.ArgumentParser(add_help=False)
+    parser.add_argument('-h', '--help', action='store_true')
     parser.add_argument('--config')
     parser.add_argument('--build-dir')
     parser.add_argument('--build')
@@ -852,13 +841,14 @@ def bootstrap(help_triggered):
     parser.add_argument('--clean', action='store_true')
     parser.add_argument('-v', '--verbose', action='count', default=0)
 
-    args = [a for a in sys.argv if a != '-h' and a != '--help']
-    args, _ = parser.parse_known_args(args)
+    return parser.parse_known_args(sys.argv)[0]
 
+def bootstrap(args):
+    """Configure, fetch, build and run the initial bootstrap"""
     # Configure initial bootstrap
     build = RustBuild()
     build.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
-    build.verbose = args.verbose
+    build.verbose = args.verbose != 0
     build.clean = args.clean
 
     # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`,
@@ -886,12 +876,12 @@ def bootstrap(help_triggered):
         with open(include_path) as included_toml:
             build.config_toml += os.linesep + included_toml.read()
 
-    config_verbose = build.get_toml('verbose', 'build')
-    if config_verbose is not None:
-        build.verbose = max(build.verbose, int(config_verbose))
+    verbose_count = args.verbose
+    config_verbose_count = build.get_toml('verbose', 'build')
+    if config_verbose_count is not None:
+        verbose_count = max(args.verbose, int(config_verbose_count))
 
     build.use_vendored_sources = build.get_toml('vendor', 'build') == 'true'
-
     build.use_locked_deps = build.get_toml('locked-deps', 'build') == 'true'
 
     build.check_vendored_status()
@@ -903,8 +893,7 @@ def bootstrap(help_triggered):
         data = json.load(f)
     build.checksums_sha256 = data["checksums_sha256"]
     build.stage0_compiler = Stage0Toolchain(data["compiler"])
-
-    build.set_dist_environment(data["config"]["dist_server"])
+    build.download_url = os.getenv("RUSTUP_DIST_SERVER") or data["config"]["dist_server"]
 
     build.build = args.build or build.build_triple()
 
@@ -914,7 +903,7 @@ def bootstrap(help_triggered):
     # Fetch/build the bootstrap
     build.download_toolchain()
     sys.stdout.flush()
-    build.build_bootstrap(args.color)
+    build.build_bootstrap(args.color, verbose_count)
     sys.stdout.flush()
 
     # Run the bootstrap
@@ -932,25 +921,32 @@ def main():
 
     # x.py help <cmd> ...
     if len(sys.argv) > 1 and sys.argv[1] == 'help':
-        sys.argv = [sys.argv[0], '-h'] + sys.argv[2:]
+        sys.argv[1] = '-h'
+
+    args = parse_args()
+    help_triggered = args.help or len(sys.argv) == 1
 
-    help_triggered = (
-        '-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1)
+    # If the user is asking for help, let them know that the whole download-and-build
+    # process has to happen before anything is printed out.
+    if help_triggered:
+        print(
+            "info: Downloading and building bootstrap before processing --help command.\n"
+            "      See src/bootstrap/README.md for help with common commands."
+        )
+
+    exit_code = 0
     try:
-        bootstrap(help_triggered)
-        if not help_triggered:
-            print("Build completed successfully in {}".format(
-                format_build_time(time() - start_time)))
+        bootstrap(args)
     except (SystemExit, KeyboardInterrupt) as error:
         if hasattr(error, 'code') and isinstance(error.code, int):
             exit_code = error.code
         else:
             exit_code = 1
             print(error)
-        if not help_triggered:
-            print("Build completed unsuccessfully in {}".format(
-                format_build_time(time() - start_time)))
-        sys.exit(exit_code)
+
+    if not help_triggered:
+        print("Build completed successfully in", format_build_time(time() - start_time))
+    sys.exit(exit_code)
 
 
 if __name__ == '__main__':
index 68d1db0160a2e7cd0872fd56dd6003245f9acc7d..07c0d2233caeb29f8a74d03a5963e25dafdcc8c0 100644 (file)
@@ -379,6 +379,9 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
     if stage >= 1 {
         cargo.rustflag("-Cembed-bitcode=yes");
     }
+    if builder.config.rust_lto == RustcLto::Off {
+        cargo.rustflag("-Clto=off");
+    }
 
     // By default, rustc does not include unwind tables unless they are required
     // for a particular target. They are not required by RISC-V targets, but
@@ -722,6 +725,13 @@ fn run(self, builder: &Builder<'_>) {
                     cargo.rustflag("-Cembed-bitcode=yes");
                 }
                 RustcLto::ThinLocal => { /* Do nothing, this is the default */ }
+                RustcLto::Off => {
+                    cargo.rustflag("-Clto=off");
+                }
+            }
+        } else {
+            if builder.config.rust_lto == RustcLto::Off {
+                cargo.rustflag("-Clto=off");
             }
         }
 
index 165502b0a41d8214d8389a075bdfe07ea2d7b26f..e5fad538969711ce0516fe242b9cbd5e654d3c34 100644 (file)
@@ -333,8 +333,9 @@ fn default_for_platform(target: &str) -> Self {
 }
 
 /// LTO mode used for compiling rustc itself.
-#[derive(Default, Clone)]
+#[derive(Default, Clone, PartialEq)]
 pub enum RustcLto {
+    Off,
     #[default]
     ThinLocal,
     Thin,
@@ -349,6 +350,7 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
             "thin-local" => Ok(RustcLto::ThinLocal),
             "thin" => Ok(RustcLto::Thin),
             "fat" => Ok(RustcLto::Fat),
+            "off" => Ok(RustcLto::Off),
             _ => Err(format!("Invalid value for rustc LTO: {}", s)),
         }
     }
index 2f4ccb825c4d8738199976676b69195e5345a445..b98b13119e8ad56b8c44c73ba4c5e26020ebff20 100644 (file)
@@ -12,6 +12,8 @@ debug-logging = true
 incremental = true
 # Print backtrace on internal compiler errors during bootstrap
 backtrace-on-ice = true
+# Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown.
+lto = "off"
 
 [llvm]
 # Will download LLVM from CI if available on your platform.
index 7bc054d3a49fc97a4be9c0fced37855268f1728a..f362c4111f107f99c8d6ee14b2dd559d4e11a6a0 100644 (file)
@@ -8,6 +8,8 @@ bench-stage = 0
 [rust]
 # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
 incremental = true
+# Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown.
+lto = "off"
 
 [llvm]
 # Will download LLVM from CI if available on your platform.
index 1be7c6777a791efc11d4c2ffa98aee146bb4ec54..bd67978a7662ee1d61c9d572d6194c8b243276c0 100644 (file)
@@ -18,6 +18,8 @@
     Config,
 };
 
+static SHOULD_FIX_BINS_AND_DYLIBS: OnceCell<bool> = OnceCell::new();
+
 /// Generic helpers that are useful anywhere in bootstrap.
 impl Config {
     pub fn is_verbose(&self) -> bool {
@@ -70,53 +72,61 @@ pub(crate) fn check_run(&self, cmd: &mut Command) -> bool {
         check_run(cmd, self.is_verbose())
     }
 
-    /// Modifies the interpreter section of 'fname' to fix the dynamic linker,
-    /// or the RPATH section, to fix the dynamic library search path
-    ///
-    /// This is only required on NixOS and uses the PatchELF utility to
-    /// change the interpreter/RPATH of ELF executables.
-    ///
-    /// Please see https://nixos.org/patchelf.html for more information
-    fn fix_bin_or_dylib(&self, fname: &Path) {
-        // FIXME: cache NixOS detection?
-        match Command::new("uname").arg("-s").stderr(Stdio::inherit()).output() {
-            Err(_) => return,
-            Ok(output) if !output.status.success() => return,
-            Ok(output) => {
-                let mut s = output.stdout;
-                if s.last() == Some(&b'\n') {
-                    s.pop();
-                }
-                if s != b"Linux" {
-                    return;
+    /// Whether or not `fix_bin_or_dylib` needs to be run; can only be true
+    /// on NixOS
+    fn should_fix_bins_and_dylibs(&self) -> bool {
+        let val = *SHOULD_FIX_BINS_AND_DYLIBS.get_or_init(|| {
+            match Command::new("uname").arg("-s").stderr(Stdio::inherit()).output() {
+                Err(_) => return false,
+                Ok(output) if !output.status.success() => return false,
+                Ok(output) => {
+                    let mut os_name = output.stdout;
+                    if os_name.last() == Some(&b'\n') {
+                        os_name.pop();
+                    }
+                    if os_name != b"Linux" {
+                        return false;
+                    }
                 }
             }
-        }
 
-        // If the user has asked binaries to be patched for Nix, then
-        // don't check for NixOS or `/lib`, just continue to the patching.
-        // NOTE: this intentionally comes after the Linux check:
-        // - patchelf only works with ELF files, so no need to run it on Mac or Windows
-        // - On other Unix systems, there is no stable syscall interface, so Nix doesn't manage the global libc.
-        if !self.patch_binaries_for_nix {
+            // If the user has asked binaries to be patched for Nix, then
+            // don't check for NixOS or `/lib`.
+            // NOTE: this intentionally comes after the Linux check:
+            // - patchelf only works with ELF files, so no need to run it on Mac or Windows
+            // - On other Unix systems, there is no stable syscall interface, so Nix doesn't manage the global libc.
+            if self.patch_binaries_for_nix {
+                return true;
+            }
+
             // Use `/etc/os-release` instead of `/etc/NIXOS`.
             // The latter one does not exist on NixOS when using tmpfs as root.
-            const NIX_IDS: &[&str] = &["ID=nixos", "ID='nixos'", "ID=\"nixos\""];
-            let os_release = match File::open("/etc/os-release") {
-                Err(e) if e.kind() == ErrorKind::NotFound => return,
+            let is_nixos = match File::open("/etc/os-release") {
+                Err(e) if e.kind() == ErrorKind::NotFound => false,
                 Err(e) => panic!("failed to access /etc/os-release: {}", e),
-                Ok(f) => f,
+                Ok(os_release) => BufReader::new(os_release).lines().any(|l| {
+                    let l = l.expect("reading /etc/os-release");
+                    matches!(l.trim(), "ID=nixos" | "ID='nixos'" | "ID=\"nixos\"")
+                }),
             };
-            if !BufReader::new(os_release).lines().any(|l| NIX_IDS.contains(&t!(l).trim())) {
-                return;
-            }
-            if Path::new("/lib").exists() {
-                return;
-            }
+            is_nixos && !Path::new("/lib").exists()
+        });
+        if val {
+            println!("info: You seem to be using Nix.");
         }
+        val
+    }
 
-        // At this point we're pretty sure the user is running NixOS or using Nix
-        println!("info: you seem to be using Nix. Attempting to patch {}", fname.display());
+    /// Modifies the interpreter section of 'fname' to fix the dynamic linker,
+    /// or the RPATH section, to fix the dynamic library search path
+    ///
+    /// This is only required on NixOS and uses the PatchELF utility to
+    /// change the interpreter/RPATH of ELF executables.
+    ///
+    /// Please see https://nixos.org/patchelf.html for more information
+    fn fix_bin_or_dylib(&self, fname: &Path) {
+        assert_eq!(SHOULD_FIX_BINS_AND_DYLIBS.get(), Some(&true));
+        println!("attempting to patch {}", fname.display());
 
         // Only build `.nix-deps` once.
         static NIX_DEPS_DIR: OnceCell<PathBuf> = OnceCell::new();
@@ -340,8 +350,10 @@ pub(crate) fn maybe_download_rustfmt(&self) -> Option<PathBuf> {
             "rustfmt",
         );
 
-        self.fix_bin_or_dylib(&bin_root.join("bin").join("rustfmt"));
-        self.fix_bin_or_dylib(&bin_root.join("bin").join("cargo-fmt"));
+        if self.should_fix_bins_and_dylibs() {
+            self.fix_bin_or_dylib(&bin_root.join("bin").join("rustfmt"));
+            self.fix_bin_or_dylib(&bin_root.join("bin").join("cargo-fmt"));
+        }
 
         self.create(&rustfmt_stamp, &channel);
         Some(rustfmt_path)
@@ -370,16 +382,21 @@ pub(crate) fn download_ci_rustc(&self, commit: &str) {
             let filename = format!("rust-src-{version}.tar.xz");
             self.download_ci_component(filename, "rust-src", commit);
 
-            self.fix_bin_or_dylib(&bin_root.join("bin").join("rustc"));
-            self.fix_bin_or_dylib(&bin_root.join("bin").join("rustdoc"));
-            self.fix_bin_or_dylib(&bin_root.join("libexec").join("rust-analyzer-proc-macro-srv"));
-            let lib_dir = bin_root.join("lib");
-            for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
-                let lib = t!(lib);
-                if lib.path().extension() == Some(OsStr::new("so")) {
-                    self.fix_bin_or_dylib(&lib.path());
+            if self.should_fix_bins_and_dylibs() {
+                self.fix_bin_or_dylib(&bin_root.join("bin").join("rustc"));
+                self.fix_bin_or_dylib(&bin_root.join("bin").join("rustdoc"));
+                self.fix_bin_or_dylib(
+                    &bin_root.join("libexec").join("rust-analyzer-proc-macro-srv"),
+                );
+                let lib_dir = bin_root.join("lib");
+                for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
+                    let lib = t!(lib);
+                    if lib.path().extension() == Some(OsStr::new("so")) {
+                        self.fix_bin_or_dylib(&lib.path());
+                    }
                 }
             }
+
             t!(fs::write(rustc_stamp, commit));
         }
     }
@@ -471,8 +488,10 @@ pub(crate) fn maybe_download_ci_llvm(&self) {
         let key = format!("{}{}", llvm_sha, self.llvm_assertions);
         if program_out_of_date(&llvm_stamp, &key) && !self.dry_run() {
             self.download_ci_llvm(&llvm_sha);
-            for entry in t!(fs::read_dir(llvm_root.join("bin"))) {
-                self.fix_bin_or_dylib(&t!(entry).path());
+            if self.should_fix_bins_and_dylibs() {
+                for entry in t!(fs::read_dir(llvm_root.join("bin"))) {
+                    self.fix_bin_or_dylib(&t!(entry).path());
+                }
             }
 
             // Update the timestamp of llvm-config to force rustc_llvm to be
@@ -487,13 +506,16 @@ pub(crate) fn maybe_download_ci_llvm(&self) {
             let llvm_config = llvm_root.join("bin").join(exe("llvm-config", self.build));
             t!(filetime::set_file_times(&llvm_config, now, now));
 
-            let llvm_lib = llvm_root.join("lib");
-            for entry in t!(fs::read_dir(&llvm_lib)) {
-                let lib = t!(entry).path();
-                if lib.extension().map_or(false, |ext| ext == "so") {
-                    self.fix_bin_or_dylib(&lib);
+            if self.should_fix_bins_and_dylibs() {
+                let llvm_lib = llvm_root.join("lib");
+                for entry in t!(fs::read_dir(&llvm_lib)) {
+                    let lib = t!(entry).path();
+                    if lib.extension().map_or(false, |ext| ext == "so") {
+                        self.fix_bin_or_dylib(&lib);
+                    }
                 }
             }
+
             t!(fs::write(llvm_stamp, key));
         }
     }
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 004601cb68b10b1dbc36f2c5e3bb37e7c86af23c..c98a52450849e9bc9bce15d17a92a5d1e40edd72 100644 (file)
@@ -1,6 +1,7 @@
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::Config;
 use crate::{t, VERSION};
+use sha2::Digest;
 use std::env::consts::EXE_SUFFIX;
 use std::fmt::Write as _;
 use std::fs::File;
@@ -10,6 +11,9 @@
 use std::str::FromStr;
 use std::{fmt, fs, io};
 
+#[cfg(test)]
+mod tests;
+
 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
 pub enum Profile {
     Compiler,
@@ -19,6 +23,13 @@ pub enum Profile {
     User,
 }
 
+/// A list of historical hashes of `src/etc/vscode_settings.json`.
+/// New entries should be appended whenever this is updated so we can detected
+/// outdated vs. user-modified settings files.
+static SETTINGS_HASHES: &[&str] =
+    &["ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8"];
+static VSCODE_SETTINGS: &str = include_str!("../etc/vscode_settings.json");
+
 impl Profile {
     fn include_path(&self, src_path: &Path) -> PathBuf {
         PathBuf::from(format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), self))
@@ -155,6 +166,7 @@ pub fn setup(config: &Config, profile: Profile) {
 
     if !config.dry_run() {
         t!(install_git_hook_maybe(&config));
+        t!(create_vscode_settings_maybe(&config));
     }
 
     println!();
@@ -351,6 +363,34 @@ fn parse_with_abbrev(input: &str) -> Result<Profile, String> {
     Ok(template)
 }
 
+#[derive(PartialEq)]
+enum PromptResult {
+    Yes,   // y/Y/yes
+    No,    // n/N/no
+    Print, // p/P/print
+}
+
+/// Prompt a user for a answer, looping until they enter an accepted input or nothing
+fn prompt_user(prompt: &str) -> io::Result<Option<PromptResult>> {
+    let mut input = String::new();
+    loop {
+        print!("{prompt} ");
+        io::stdout().flush()?;
+        input.clear();
+        io::stdin().read_line(&mut input)?;
+        match input.trim().to_lowercase().as_str() {
+            "y" | "yes" => return Ok(Some(PromptResult::Yes)),
+            "n" | "no" => return Ok(Some(PromptResult::No)),
+            "p" | "print" => return Ok(Some(PromptResult::Print)),
+            "" => return Ok(None),
+            _ => {
+                eprintln!("error: unrecognized option '{}'", input.trim());
+                eprintln!("note: press Ctrl+C to exit");
+            }
+        };
+    }
+}
+
 // install a git hook to automatically run tidy, if they want
 fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
     let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
@@ -363,43 +403,98 @@ fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
         return Ok(());
     }
 
-    let mut input = String::new();
-    println!();
     println!(
-        "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
+        "\nRust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
 If you'd like, x.py can install a git hook for you that will automatically run `test tidy` before
 pushing your code to ensure your code is up to par. If you decide later that this behavior is
 undesirable, simply delete the `pre-push` file from .git/hooks."
     );
 
-    let should_install = loop {
-        print!("Would you like to install the git hook?: [y/N] ");
-        io::stdout().flush()?;
-        input.clear();
-        io::stdin().read_line(&mut input)?;
-        break match input.trim().to_lowercase().as_str() {
-            "y" | "yes" => true,
-            "n" | "no" | "" => false,
-            _ => {
-                eprintln!("error: unrecognized option '{}'", input.trim());
-                eprintln!("note: press Ctrl+C to exit");
-                continue;
-            }
-        };
-    };
-
-    if should_install {
-        let src = config.src.join("src").join("etc").join("pre-push.sh");
-        match fs::hard_link(src, &dst) {
-            Err(e) => eprintln!(
+    if prompt_user("Would you like to install the git hook?: [y/N]")? != Some(PromptResult::Yes) {
+        println!("Ok, skipping installation!");
+        return Ok(());
+    }
+    let src = config.src.join("src").join("etc").join("pre-push.sh");
+    match fs::hard_link(src, &dst) {
+        Err(e) => {
+            eprintln!(
                 "error: could not create hook {}: do you already have the git hook installed?\n{}",
                 dst.display(),
                 e
-            ),
-            Ok(_) => println!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"),
+            );
+            return Err(e);
+        }
+        Ok(_) => println!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"),
+    };
+    Ok(())
+}
+
+/// Create a `.vscode/settings.json` file for rustc development, or just print it
+fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> {
+    let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap();
+    let vscode_settings = config.src.join(".vscode").join("settings.json");
+    // If None, no settings.json exists
+    // If Some(true), is a previous version of settings.json
+    // If Some(false), is not a previous version (i.e. user modified)
+    // If it's up to date we can just skip this
+    let mut mismatched_settings = None;
+    if let Ok(current) = fs::read_to_string(&vscode_settings) {
+        let mut hasher = sha2::Sha256::new();
+        hasher.update(&current);
+        let hash = hex::encode(hasher.finalize().as_slice());
+        if hash == *current_hash {
+            return Ok(());
+        } else if historical_hashes.contains(&hash.as_str()) {
+            mismatched_settings = Some(true);
+        } else {
+            mismatched_settings = Some(false);
+        }
+    }
+    println!(
+        "\nx.py can automatically install the recommended `.vscode/settings.json` file for rustc development"
+    );
+    match mismatched_settings {
+        Some(true) => eprintln!(
+            "warning: existing `.vscode/settings.json` is out of date, x.py will update it"
+        ),
+        Some(false) => eprintln!(
+            "warning: existing `.vscode/settings.json` has been modified by user, x.py will back it up and replace it"
+        ),
+        _ => (),
+    }
+    let should_create = match prompt_user(
+        "Would you like to create/update `settings.json`, or only print suggested settings?: [y/p/N]",
+    )? {
+        Some(PromptResult::Yes) => true,
+        Some(PromptResult::Print) => false,
+        _ => {
+            println!("Ok, skipping settings!");
+            return Ok(());
+        }
+    };
+    if should_create {
+        let path = config.src.join(".vscode");
+        if !path.exists() {
+            fs::create_dir(&path)?;
+        }
+        let verb = match mismatched_settings {
+            // exists but outdated, we can replace this
+            Some(true) => "Updated",
+            // exists but user modified, back it up
+            Some(false) => {
+                // exists and is not current version or outdated, so back it up
+                let mut backup = vscode_settings.clone();
+                backup.set_extension("bak");
+                eprintln!("warning: copying `settings.json` to `settings.json.bak`");
+                fs::copy(&vscode_settings, &backup)?;
+                "Updated"
+            }
+            _ => "Created",
         };
+        fs::write(&vscode_settings, &VSCODE_SETTINGS)?;
+        println!("{verb} `.vscode/settings.json`");
     } else {
-        println!("Ok, skipping installation!");
+        println!("\n{VSCODE_SETTINGS}");
     }
     Ok(())
 }
diff --git a/src/bootstrap/setup/tests.rs b/src/bootstrap/setup/tests.rs
new file mode 100644 (file)
index 0000000..dcf9d18
--- /dev/null
@@ -0,0 +1,14 @@
+use super::{SETTINGS_HASHES, VSCODE_SETTINGS};
+use sha2::Digest;
+
+#[test]
+fn check_matching_settings_hash() {
+    let mut hasher = sha2::Sha256::new();
+    hasher.update(&VSCODE_SETTINGS);
+    let hash = hex::encode(hasher.finalize().as_slice());
+    assert_eq!(
+        &hash,
+        SETTINGS_HASHES.last().unwrap(),
+        "Update `SETTINGS_HASHES` with the new hash of `src/etc/vscode_settings.json`"
+    );
+}
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 c8d1ff9aefb7e49c96b5c151edb1f351afa88193..a6d84a3c18a5f2802597b6d751cb8e95c95b53ee 100755 (executable)
@@ -19,18 +19,18 @@ import shutil
 import signal
 import subprocess
 import sys
-from typing import ClassVar, List
+from typing import ClassVar, List, Optional
 
 
 @dataclass
 class TestEnvironment:
     rust_dir: str
     sdk_dir: str
-    target_arch: str
-    package_server_pid: int = None
-    emu_addr: str = None
-    libstd_name: str = None
-    libtest_name: str = None
+    target: str
+    package_server_pid: Optional[int] = None
+    emu_addr: Optional[str] = None
+    libstd_name: Optional[str] = None
+    libtest_name: Optional[str] = None
     verbose: bool = False
 
     @staticmethod
@@ -40,6 +40,15 @@ class TestEnvironment:
             return os.path.abspath(tmp_dir)
         return os.path.join(os.path.dirname(__file__), "tmp~")
 
+    @staticmethod
+    def triple_to_arch(triple):
+        if "x86_64" in triple:
+            return "x64"
+        elif "aarch64" in triple:
+            return "arm64"
+        else:
+            raise Exception(f"Unrecognized target triple {triple}")
+
     @classmethod
     def env_file_path(cls):
         return os.path.join(cls.tmp_dir(), "test_env.json")
@@ -49,7 +58,7 @@ class TestEnvironment:
         return cls(
             os.path.abspath(args.rust),
             os.path.abspath(args.sdk),
-            args.target_arch,
+            args.target,
             verbose=args.verbose,
         )
 
@@ -60,7 +69,7 @@ class TestEnvironment:
             return cls(
                 test_env["rust_dir"],
                 test_env["sdk_dir"],
-                test_env["target_arch"],
+                test_env["target"],
                 libstd_name=test_env["libstd_name"],
                 libtest_name=test_env["libtest_name"],
                 emu_addr=test_env["emu_addr"],
@@ -68,13 +77,6 @@ class TestEnvironment:
                 verbose=test_env["verbose"],
             )
 
-    def image_name(self):
-        if self.target_arch == "x64":
-            return "qemu-x64"
-        if self.target_arch == "arm64":
-            return "qemu-arm64"
-        raise Exception(f"Unrecognized target architecture {self.target_arch}")
-
     def write_to_file(self):
         with open(self.env_file_path(), "w", encoding="utf-8") as f:
             f.write(json.dumps(self.__dict__))
@@ -108,13 +110,6 @@ class TestEnvironment:
     def repo_dir(self):
         return os.path.join(self.tmp_dir(), self.TEST_REPO_NAME)
 
-    def rustlib_dir(self):
-        if self.target_arch == "x64":
-            return "x86_64-unknown-fuchsia"
-        if self.target_arch == "arm64":
-            return "aarch64-unknown-fuchsia"
-        raise Exception(f"Unrecognized target architecture {self.target_arch}")
-
     def libs_dir(self):
         return os.path.join(
             self.rust_dir,
@@ -125,7 +120,7 @@ class TestEnvironment:
         return os.path.join(
             self.libs_dir(),
             "rustlib",
-            self.rustlib_dir(),
+            self.target,
             "lib",
         )
 
@@ -384,7 +379,7 @@ class TestEnvironment:
                 "--emulator-log",
                 self.emulator_log_path(),
                 "--image-name",
-                self.image_name(),
+                "qemu-" + self.triple_to_arch(self.target),
             ],
             stdout=self.subprocess_output(),
             stderr=self.subprocess_output(),
@@ -642,11 +637,11 @@ class TestEnvironment:
                         package_dir=package_dir,
                         package_name=package_name,
                         rust_dir=self.rust_dir,
-                        rustlib_dir=self.rustlib_dir(),
+                        rustlib_dir=self.target,
                         sdk_dir=self.sdk_dir,
                         libstd_name=self.libstd_name,
                         libtest_name=self.libtest_name,
-                        target_arch=self.target_arch,
+                        target_arch=self.triple_to_arch(self.target),
                     )
                 )
                 for shared_lib in shared_libs:
@@ -969,8 +964,8 @@ def main():
         action="store_true",
     )
     start_parser.add_argument(
-        "--target-arch",
-        help="the architecture of the image to test",
+        "--target",
+        help="the target platform to test",
         required=True,
     )
     start_parser.set_defaults(func=start)
index 5e676a470a034e2a8ea842da13b4ee2b94761308..3c128c0ca251b514142c020fbc7c6409ee843a06 100644 (file)
@@ -33,6 +33,7 @@ x--expand-yaml-anchors--remove:
 
   - &shared-ci-variables
     CI_JOB_NAME: ${{ matrix.name }}
+    CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
 
   - &public-variables
     SCCACHE_BUCKET: rust-lang-ci-sccache2
@@ -77,7 +78,7 @@ x--expand-yaml-anchors--remove:
     <<: *base-job
 
   - &job-macos-xl
-    os: macos-12-xl
+    os: macos-latest  # We don't have an XL builder for this
     <<: *base-job
 
   - &job-windows-xl
@@ -306,8 +307,6 @@ jobs:
           - name: x86_64-gnu-tools
             <<: *job-linux-xl
             tidy: false
-            env:
-              CI_ONLY_WHEN_SUBMODULES_CHANGED: 1
 
   auto:
     permissions:
index 0db9c993eecb407f2fd72cb4a3a0a76ef3535cb4..93dccb54c4e38463f07e9b013229868566199b9f 100755 (executable)
@@ -45,6 +45,8 @@ fi
 ci_dir=`cd $(dirname $0) && pwd`
 source "$ci_dir/shared.sh"
 
+export CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
+
 if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try || isCiBranch try-perf; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.metrics"
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 29e70129a62ed42527835c9be04dfe89ecbdb283..0f165b268ba3b9d01091d8d6f9e09870b172ea3a 100644 (file)
@@ -697,7 +697,7 @@ test environment with:
 src/ci/docker/scripts/fuchsia-test-runner.py start
     --rust ${RUST_SRC_PATH}/install
     --sdk ${SDK_PATH}
-    --target-arch {x64,arm64}
+    --target-triple {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia}
 ```
 
 Where `${RUST_SRC_PATH}/install` is the `prefix` set in `config.toml` and
index 29b48bb1ee0b78a8be8127a31031cc935d35de07..4ab1c36f976525dfcfb3a44e568d11305b8e6efd 100644 (file)
@@ -99,6 +99,84 @@ let Foo {
 );
 ```
 
+#### else blocks (let-else statements)
+
+If a let statement contains an `else` component, also known as a let-else statement,
+then the `else` component should be formatted according to the same rules as the `else` block
+in [control flow expressions (i.e. if-else, and if-let-else expressions)](./expressions.md#control-flow-expressions).
+Apply the same formatting rules to the components preceding
+the `else` block (i.e. the `let pattern: Type = initializer_expr ...` portion)
+as described [above](#let-statements)
+
+Similarly to if-else expressions, if the initializer
+expression is multi-lined, then the `else` keyword and opening brace of the block (i.e. `else {`)
+should be put on the same line as the end of the initializer
+expression with a preceding space if all the following are true:
+
+* The initializer expression ends with one or more closing
+  parentheses, square brackets, and/or braces
+* There is nothing else on that line
+* That line is not indented beyond the indent of the first line containing the `let` keyword
+
+For example:
+
+```rust
+let Some(x) = y.foo(
+    "abc",
+    fairly_long_identifier,
+    "def",
+    "123456",
+    "string",
+    "cheese",
+) else {
+    bar()
+}
+```
+
+Otherwise, the `else` keyword and opening brace should be placed on the next line after the end of the initializer expression, and should not be indented (the `else` keyword should be aligned with the `let` keyword).
+
+For example:
+
+```rust
+let Some(x) = abcdef()
+    .foo(
+        "abc",
+        some_really_really_really_long_ident,
+        "ident",
+        "123456",
+    )
+    .bar()
+    .baz()
+    .qux("fffffffffffffffff")
+else {
+    foo_bar()
+}
+```
+
+##### Single line let-else statements
+
+The entire let-else statement may be formatted on a single line if all the following are true:
+
+* the entire statement is *short*
+* the `else` block contains a single-line expression and no statements
+* the `else` block contains no comments
+* the let statement components preceding the `else` block can be formatted on a single line
+
+```rust
+let Some(1) = opt else { return };
+
+let Some(1) = opt else {
+    return;
+};
+
+let Some(1) = opt else {
+    // nope
+    return
+};
+```
+
+Formatters may allow users to configure the value of the threshold
+used to determine whether a let-else statement is *short*.
 
 ### Macros in statement position
 
diff --git a/src/etc/vscode_settings.json b/src/etc/vscode_settings.json
new file mode 100644 (file)
index 0000000..cd61a38
--- /dev/null
@@ -0,0 +1,26 @@
+{
+    "rust-analyzer.checkOnSave.overrideCommand": [
+        "python3",
+        "x.py",
+        "check",
+        "--json-output"
+    ],
+    "rust-analyzer.linkedProjects": ["src/bootstrap/Cargo.toml", "Cargo.toml"],
+    "rust-analyzer.rustfmt.overrideCommand": [
+        "./build/host/rustfmt/bin/rustfmt",
+        "--edition=2021"
+    ],
+    "rust-analyzer.procMacro.server": "./build/host/stage0/libexec/rust-analyzer-proc-macro-srv",
+    "rust-analyzer.procMacro.enable": true,
+    "rust-analyzer.cargo.buildScripts.enable": true,
+    "rust-analyzer.cargo.buildScripts.invocationLocation": "root",
+    "rust-analyzer.cargo.buildScripts.invocationStrategy": "once",
+    "rust-analyzer.cargo.buildScripts.overrideCommand": [
+        "python3",
+        "x.py",
+        "check",
+        "--json-output"
+    ],
+    "rust-analyzer.cargo.sysroot": "./build/host/stage0-sysroot",
+    "rust-analyzer.rustc.source": "./Cargo.toml"
+}
index e2ced191a00c0e267eaf71e3d353eed379d7bd6b..80493b100bb45cecf4271e01c6be350b655d150e 100644 (file)
@@ -2213,21 +2213,17 @@ fn clean_maybe_renamed_item<'tcx>(
             get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut extra_attrs);
         }
 
-        if !extra_attrs.is_empty() {
+        let mut item = if !extra_attrs.is_empty() {
             extra_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
             let attrs = Attributes::from_ast(&extra_attrs);
             let cfg = extra_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
 
-            vec![Item::from_def_id_and_attrs_and_parts(
-                def_id,
-                Some(name),
-                kind,
-                Box::new(attrs),
-                cfg,
-            )]
+            Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg)
         } else {
-            vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
-        }
+            Item::from_def_id_and_parts(def_id, Some(name), kind, cx)
+        };
+        item.inline_stmt_id = import_id.map(|def_id| def_id.to_def_id());
+        vec![item]
     })
 }
 
index 33404a76835975da4e656f3f8bff6f5952116202..8a7a8ea5fd1f268a69c6e7f39eb319030f032896 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)?;
                     }
                 }
 
@@ -289,7 +289,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
                 if f.alternate() {
                     f.write_str(" ")?;
                 } else {
-                    f.write_str("<br>")?;
+                    f.write_str("\n")?;
                 }
 
                 match pred {
@@ -352,23 +352,31 @@ 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;");
+            br_with_padding.push_str("\n");
+
+            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);
+            let where_preds = where_preds.to_string().replace("\n", &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 {
-                // insert a <br> tag after a single space but before multiple spaces at the start
+                // insert a newline after a single space but before multiple spaces at the start
                 if indent == 0 {
-                    format!("<br><span class=\"where\">where{where_preds}</span>")
+                    format!("\n<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
                 }
@@ -1307,7 +1315,8 @@ pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
 
     /// * `header_len`: The length of the function header and name. In other words, the number of
     ///   characters in the function declaration up to but not including the parentheses.
-    ///   <br>Used to determine line-wrapping.
+    ///   This is expected to go into a `<pre>`/`code-header` block, so indentation and newlines
+    ///   are preserved.
     /// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is
     ///   necessary.
     pub(crate) fn full_print<'a, 'tcx: 'a>(
@@ -1355,7 +1364,7 @@ fn inner_full_print(
                 }
             } else {
                 if i > 0 {
-                    args.push_str("<br>");
+                    args.push_str("\n");
                 }
                 if input.is_const {
                     args.push_str("const ");
@@ -1381,7 +1390,7 @@ fn inner_full_print(
         let mut args = args.into_inner();
 
         if self.c_variadic {
-            args.push_str(",<br> ...");
+            args.push_str(",\n ...");
             args_plain.push_str(", ...");
         }
 
@@ -1391,24 +1400,20 @@ 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!("\n{}", " ".repeat(indent + 4));
+            let close_pad = format!("\n{}", " ".repeat(indent));
             format!(
                 "({pad}{args}{close}){arrow}",
                 pad = if self.inputs.values.is_empty() { "" } else { &full_pad },
-                args = args.replace("<br>", &full_pad),
+                args = args.replace("\n", &full_pad),
                 close = close_pad,
                 arrow = arrow
             )
         } else {
-            format!("({args}){arrow}", args = args.replace("<br>", " "), arrow = arrow)
+            format!("({args}){arrow}", args = args.replace("\n", " "), arrow = arrow)
         };
 
-        if f.alternate() {
-            write!(f, "{}", output.replace("<br>", "\n"))
-        } else {
-            write!(f, "{}", output)
-        }
+        write!(f, "{}", output)
     }
 }
 
@@ -1611,7 +1616,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 6b71ecc24bde6f8e3604729a57e0df84172ea715..54749e9a3171856b0ef735ac240fc0b21225de59 100644 (file)
@@ -138,7 +138,7 @@ fn collect(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> {
         Ok((ret, krates))
     }
 
-    /// Read a file and return all lines that match the <code>"{crate}":{data},\</code> format,
+    /// Read a file and return all lines that match the <code>"{crate}":{data},\ </code> format,
     /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`.
     ///
     /// This forms the payload of files that look like this:
index dad27c66a3de59f586cf5a7ad1ad67f9ebb323f7..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;
 }
 
@@ -814,8 +816,11 @@ so that we can apply CSS-filters to change the arrow color in themes */
        background-repeat: no-repeat;
        background-size: 20px;
        background-position: calc(100% - 2px) 56%;
-       /* image is black color */
-       background-image: url("down-arrow-927217e04c7463ac.svg");
+       /* down arrow (image is black color) */
+       background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
+       width="128" height="128" viewBox="-30 -20 176 176"><path d="M111,40.5L64,87.499L17,40.5" \
+       fill="none" stroke="black" strike-linecap="square" stroke-miterlimit="10" stroke-width="12"/> \
+       </svg>');
        /* changes the arrow image color */
        filter: var(--crate-search-div-filter);
 }
@@ -1171,6 +1176,7 @@ a.test-arrow:hover {
 .item-spacer {
        width: 100%;
        height: 12px;
+       display: block;
 }
 
 .out-of-band > span.since {
@@ -1444,7 +1450,10 @@ details.toggle > summary.hideme > span {
 }
 
 details.toggle > summary::before {
-       background: url("toggle-plus-1092eb4930d581b0.svg") no-repeat top left;
+       /* toggle plus */
+       background: url('data:image/svg+xml,<svg width="17" height="17" \
+shape-rendering="crispEdges" stroke="black" fill="none" xmlns="http://www.w3.org/2000/svg"><path \
+d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7M8.5 12V8.625v0V5"/></svg>') no-repeat top left;
        content: "";
        cursor: pointer;
        width: 16px;
@@ -1522,7 +1531,10 @@ details.toggle[open] > summary.hideme > span {
 }
 
 details.toggle[open] > summary::before {
-       background: url("toggle-minus-31bbd6e4c77f5c96.svg") no-repeat top left;
+       /* toggle minus */
+       background: url('data:image/svg+xml,<svg width="17" height="17" \
+shape-rendering="crispEdges" stroke="black" fill="none" xmlns="http://www.w3.org/2000/svg"><path \
+d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7"/></svg>') no-repeat top left;
 }
 
 details.toggle[open] > summary::after {
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;
-}
diff --git a/src/librustdoc/html/static/images/down-arrow.svg b/src/librustdoc/html/static/images/down-arrow.svg
deleted file mode 100644 (file)
index 5d76a64..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" width="128" height="128" enable-background="new 0 0 128 128" version="1.1" viewBox="-30 -20 176 176" xml:space="preserve"><g><line x1="111" x2="64" y1="40.5" y2="87.499" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/><line x1="64" x2="17" y1="87.499" y2="40.5" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/></g></svg>
\ No newline at end of file
diff --git a/src/librustdoc/html/static/images/toggle-minus.svg b/src/librustdoc/html/static/images/toggle-minus.svg
deleted file mode 100644 (file)
index 7315478..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="17" height="17" shape-rendering="crispEdges" stroke="#000" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7"/></svg>
\ No newline at end of file
diff --git a/src/librustdoc/html/static/images/toggle-plus.svg b/src/librustdoc/html/static/images/toggle-plus.svg
deleted file mode 100644 (file)
index 08b1703..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="17" height="17" shape-rendering="crispEdges" stroke="#000" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7M8.5 12V8.625v0V5"/></svg>
\ No newline at end of file
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 b48b82307ebc3c672a87b2af3765250ea6081748..767b974cc9109f6c0c35fecf71a1bff09dde17b9 100644 (file)
@@ -102,9 +102,6 @@ pub(crate) fn for_each<E>(f: impl Fn(&StaticFile) -> Result<(), E>) -> Result<()
     scrape_examples_js => "static/js/scrape-examples.js",
     wheel_svg => "static/images/wheel.svg",
     clipboard_svg => "static/images/clipboard.svg",
-    down_arrow_svg => "static/images/down-arrow.svg",
-    toggle_minus_png => "static/images/toggle-minus.svg",
-    toggle_plus_png => "static/images/toggle-plus.svg",
     copyright => "static/COPYRIGHT.txt",
     license_apache => "static/LICENSE-APACHE.txt",
     license_mit => "static/LICENSE-MIT.txt",
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 5adc0d2a40e41bf2944e0aa079c169decf4fb253..7c5c6eb3d2bbf1b5ee5b713763a09d05749240cc 100644 (file)
@@ -222,7 +222,7 @@ fn mod_item_in(&mut self, _item: &clean::Item) -> Result<(), Error> {
     fn after_krate(&mut self) -> Result<(), Error> {
         debug!("Done with crate");
 
-        debug!("Adding Primitve impls");
+        debug!("Adding Primitive impls");
         for primitive in Rc::clone(&self.cache).primitive_locations.values() {
             self.get_impls(*primitive);
         }
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 e07a788a72a41e53bc3ea98827579b4717067dc4..8c733ddefc0a5a1efe02dd3d95647f85533a297b 100644 (file)
@@ -1,4 +1,6 @@
 //! Strip all doc(hidden) items from the output.
+
+use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
 use std::mem;
 
@@ -7,6 +9,7 @@
 use crate::core::DocContext;
 use crate::fold::{strip_item, DocFolder};
 use crate::passes::{ImplStripper, Pass};
+use crate::visit_ast::inherits_doc_hidden;
 
 pub(crate) const STRIP_HIDDEN: Pass = Pass {
     name: "strip-hidden",
@@ -21,7 +24,12 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
 
     // strip all #[doc(hidden)] items
     let krate = {
-        let mut stripper = Stripper { retained: &mut retained, update_retained: true };
+        let mut stripper = Stripper {
+            retained: &mut retained,
+            update_retained: true,
+            tcx: cx.tcx,
+            is_in_hidden_item: false,
+        };
         stripper.fold_crate(krate)
     };
 
@@ -36,40 +44,89 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
     stripper.fold_crate(krate)
 }
 
-struct Stripper<'a> {
+struct Stripper<'a, 'tcx> {
     retained: &'a mut ItemIdSet,
     update_retained: bool,
+    tcx: TyCtxt<'tcx>,
+    is_in_hidden_item: bool,
+}
+
+impl<'a, 'tcx> Stripper<'a, 'tcx> {
+    fn set_is_in_hidden_item_and_fold(&mut self, is_in_hidden_item: bool, i: Item) -> Item {
+        let prev = self.is_in_hidden_item;
+        self.is_in_hidden_item |= is_in_hidden_item;
+        let ret = self.fold_item_recur(i);
+        self.is_in_hidden_item = prev;
+        ret
+    }
+
+    /// In case `i` is a non-hidden impl block, then we special-case it by changing the value
+    /// of `is_in_hidden_item` to `true` because the impl children inherit its visibility.
+    fn recurse_in_impl(&mut self, i: Item) -> Item {
+        let prev = mem::replace(&mut self.is_in_hidden_item, false);
+        let ret = self.fold_item_recur(i);
+        self.is_in_hidden_item = prev;
+        ret
+    }
 }
 
-impl<'a> DocFolder for Stripper<'a> {
+impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
-        if i.attrs.lists(sym::doc).has_word(sym::hidden) {
-            debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
-            // Use a dedicated hidden item for fields, variants, and modules.
-            // We need to keep private fields and variants, so that the docs
-            // can show a placeholder "// some variants omitted". We need to keep
-            // private modules, because they can contain impl blocks, and impl
-            // block privacy is inherited from the type and trait, not from the
-            // module it's defined in. Both of these are marked "stripped," and
-            // not included in the final docs, but since they still have an effect
-            // on the final doc, cannot be completely removed from the Clean IR.
-            match *i.kind {
-                clean::StructFieldItem(..) | clean::ModuleItem(..) | clean::VariantItem(..) => {
-                    // We need to recurse into stripped modules to
-                    // strip things like impl methods but when doing so
-                    // we must not add any items to the `retained` set.
-                    let old = mem::replace(&mut self.update_retained, false);
-                    let ret = strip_item(self.fold_item_recur(i));
-                    self.update_retained = old;
-                    return Some(ret);
-                }
-                _ => return None,
+        let has_doc_hidden = i.attrs.lists(sym::doc).has_word(sym::hidden);
+        let is_impl = matches!(*i.kind, clean::ImplItem(..));
+        let mut is_hidden = has_doc_hidden;
+        if !is_impl {
+            is_hidden = self.is_in_hidden_item || has_doc_hidden;
+            if !is_hidden && i.inline_stmt_id.is_none() {
+                // We don't need to check if it's coming from a reexport since the reexport itself was
+                // already checked.
+                is_hidden = i
+                    .item_id
+                    .as_def_id()
+                    .and_then(|def_id| def_id.as_local())
+                    .map(|def_id| inherits_doc_hidden(self.tcx, def_id))
+                    .unwrap_or(false);
             }
-        } else {
+        }
+        if !is_hidden {
             if self.update_retained {
                 self.retained.insert(i.item_id);
             }
+            return Some(if is_impl {
+                self.recurse_in_impl(i)
+            } else {
+                self.set_is_in_hidden_item_and_fold(false, i)
+            });
+        }
+        debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
+        // Use a dedicated hidden item for fields, variants, and modules.
+        // We need to keep private fields and variants, so that the docs
+        // can show a placeholder "// some variants omitted". We need to keep
+        // private modules, because they can contain impl blocks, and impl
+        // block privacy is inherited from the type and trait, not from the
+        // module it's defined in. Both of these are marked "stripped," and
+        // not included in the final docs, but since they still have an effect
+        // on the final doc, cannot be completely removed from the Clean IR.
+        match *i.kind {
+            clean::StructFieldItem(..) | clean::ModuleItem(..) | clean::VariantItem(..) => {
+                // We need to recurse into stripped modules to
+                // strip things like impl methods but when doing so
+                // we must not add any items to the `retained` set.
+                let old = mem::replace(&mut self.update_retained, false);
+                let ret = strip_item(self.set_is_in_hidden_item_and_fold(true, i));
+                self.update_retained = old;
+                Some(ret)
+            }
+            _ => {
+                let ret = self.set_is_in_hidden_item_and_fold(true, i);
+                if has_doc_hidden {
+                    // If the item itself has `#[doc(hidden)]`, then we simply remove it.
+                    None
+                } else {
+                    // However if it's a "descendant" of a `#[doc(hidden)]` item, then we strip it.
+                    Some(strip_item(ret))
+                }
+            }
         }
-        Some(self.fold_item_recur(i))
     }
 }
index a89d6fa83983d685e8a6baf94d63327320beca71..088cb3f339492be74fc4e8091b5693f7e2427fdc 100644 (file)
@@ -5,7 +5,9 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet};
+use rustc_hir::intravisit::{walk_item, Visitor};
 use rustc_hir::{Node, CRATE_HIR_ID};
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{DefIdTree, TyCtxt};
 use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -53,19 +55,26 @@ fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<Symbol> {
     std::iter::once(crate_name).chain(relative).collect()
 }
 
-pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: LocalDefId) -> bool {
-    while let Some(id) = tcx.opt_local_parent(node) {
-        node = id;
-        if tcx.is_doc_hidden(node.to_def_id()) {
+pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut def_id: LocalDefId) -> bool {
+    let hir = tcx.hir();
+    while let Some(id) = tcx.opt_local_parent(def_id) {
+        def_id = id;
+        if tcx.is_doc_hidden(def_id.to_def_id()) {
             return true;
+        } else if let Some(node) = hir.find_by_def_id(def_id) &&
+            matches!(
+                node,
+                hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }),
+            )
+        {
+            // `impl` blocks stand a bit on their own: unless they have `#[doc(hidden)]` directly
+            // on them, they don't inherit it from the parent context.
+            return false;
         }
     }
     false
 }
 
-// Also, is there some reason that this doesn't use the 'visit'
-// framework from syntax?.
-
 pub(crate) struct RustdocVisitor<'a, 'tcx> {
     cx: &'a mut core::DocContext<'tcx>,
     view_item_stack: LocalDefIdSet,
@@ -73,6 +82,7 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> {
     /// Are the current module and all of its parents public?
     inside_public_path: bool,
     exact_paths: DefIdMap<Vec<Symbol>>,
+    modules: Vec<Module<'tcx>>,
 }
 
 impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
@@ -80,12 +90,19 @@ pub(crate) fn new(cx: &'a mut core::DocContext<'tcx>) -> RustdocVisitor<'a, 'tcx
         // If the root is re-exported, terminate all recursion.
         let mut stack = LocalDefIdSet::default();
         stack.insert(CRATE_DEF_ID);
+        let om = Module::new(
+            cx.tcx.crate_name(LOCAL_CRATE),
+            CRATE_DEF_ID,
+            cx.tcx.hir().root_module().spans.inner_span,
+        );
+
         RustdocVisitor {
             cx,
             view_item_stack: stack,
             inlining: false,
             inside_public_path: true,
             exact_paths: Default::default(),
+            modules: vec![om],
         }
     }
 
@@ -95,12 +112,10 @@ fn store_path(&mut self, did: DefId) {
     }
 
     pub(crate) fn visit(mut self) -> Module<'tcx> {
-        let mut top_level_module = self.visit_mod_contents(
-            CRATE_DEF_ID,
-            self.cx.tcx.hir().root_module(),
-            self.cx.tcx.crate_name(LOCAL_CRATE),
-            None,
-        );
+        let root_module = self.cx.tcx.hir().root_module();
+        self.visit_mod_contents(CRATE_DEF_ID, root_module);
+
+        let mut top_level_module = self.modules.pop().unwrap();
 
         // `#[macro_export] macro_rules!` items are reexported at the top level of the
         // crate, regardless of where they're defined. We want to document the
@@ -115,15 +130,13 @@ pub(crate) fn visit(mut self) -> Module<'tcx> {
         // macro in the same module.
         let mut inserted = FxHashSet::default();
         for export in self.cx.tcx.module_reexports(CRATE_DEF_ID).unwrap_or(&[]) {
-            if let Res::Def(DefKind::Macro(_), def_id) = export.res {
-                if let Some(local_def_id) = def_id.as_local() {
-                    if self.cx.tcx.has_attr(def_id, sym::macro_export) {
-                        if inserted.insert(def_id) {
-                            let item = self.cx.tcx.hir().expect_item(local_def_id);
-                            top_level_module.items.push((item, None, None));
-                        }
-                    }
-                }
+            if let Res::Def(DefKind::Macro(_), def_id) = export.res &&
+                let Some(local_def_id) = def_id.as_local() &&
+                self.cx.tcx.has_attr(def_id, sym::macro_export) &&
+                inserted.insert(def_id)
+            {
+                    let item = self.cx.tcx.hir().expect_item(local_def_id);
+                    top_level_module.items.push((item, None, None));
             }
         }
 
@@ -157,23 +170,22 @@ pub(crate) fn visit(mut self) -> Module<'tcx> {
         top_level_module
     }
 
-    fn visit_mod_contents(
-        &mut self,
-        def_id: LocalDefId,
-        m: &'tcx hir::Mod<'tcx>,
-        name: Symbol,
-        parent_id: Option<LocalDefId>,
-    ) -> Module<'tcx> {
-        let mut om = Module::new(name, def_id, m.spans.inner_span);
+    /// This method will go through the given module items in two passes:
+    /// 1. The items which are not glob imports/reexports.
+    /// 2. The glob imports/reexports.
+    fn visit_mod_contents(&mut self, def_id: LocalDefId, m: &'tcx hir::Mod<'tcx>) {
+        debug!("Going through module {:?}", m);
         // Keep track of if there were any private modules in the path.
         let orig_inside_public_path = self.inside_public_path;
         self.inside_public_path &= self.cx.tcx.local_visibility(def_id).is_public();
+
+        // Reimplementation of `walk_mod` because we need to do it in two passes (explanations in
+        // the second loop):
         for &i in m.item_ids {
             let item = self.cx.tcx.hir().item(i);
-            if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
-                continue;
+            if !matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
+                self.visit_item(item);
             }
-            self.visit_item(item, None, &mut om, parent_id);
         }
         for &i in m.item_ids {
             let item = self.cx.tcx.hir().item(i);
@@ -181,11 +193,11 @@ fn visit_mod_contents(
             // Later passes in rustdoc will de-duplicate by name and kind, so if glob-
             // imported items appear last, then they'll be the ones that get discarded.
             if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
-                self.visit_item(item, None, &mut om, parent_id);
+                self.visit_item(item);
             }
         }
         self.inside_public_path = orig_inside_public_path;
-        om
+        debug!("Leaving module {:?}", m);
     }
 
     /// Tries to resolve the target of a `pub use` statement and inlines the
@@ -203,7 +215,6 @@ fn maybe_inline_local(
         res: Res,
         renamed: Option<Symbol>,
         glob: bool,
-        om: &mut Module<'tcx>,
         please_inline: bool,
     ) -> bool {
         debug!("maybe_inline_local res: {:?}", res);
@@ -213,33 +224,30 @@ fn maybe_inline_local(
         }
 
         let tcx = self.cx.tcx;
-        let Some(res_did) = res.opt_def_id() else {
+        let Some(ori_res_did) = res.opt_def_id() else {
             return false;
         };
 
         let use_attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id));
         // Don't inline `doc(hidden)` imports so they can be stripped at a later stage.
         let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline)
-            || tcx.is_doc_hidden(def_id.to_def_id());
+            || use_attrs.lists(sym::doc).has_word(sym::hidden);
 
         // For cross-crate impl inlining we need to know whether items are
         // reachable in documentation -- a previously unreachable item can be
         // made reachable by cross-crate inlining which we're checking here.
         // (this is done here because we need to know this upfront).
-        if !res_did.is_local() && !is_no_inline {
-            crate::visit_lib::lib_embargo_visit_item(self.cx, res_did);
+        if !ori_res_did.is_local() && !is_no_inline {
+            crate::visit_lib::lib_embargo_visit_item(self.cx, ori_res_did);
             return false;
         }
 
-        let Some(res_did) = res_did.as_local() else {
+        let Some(res_did) = ori_res_did.as_local() else {
             return false;
         };
 
-        let is_private = !self
-            .cx
-            .cache
-            .effective_visibilities
-            .is_directly_public(self.cx.tcx, res_did.to_def_id());
+        let is_private =
+            !self.cx.cache.effective_visibilities.is_directly_public(self.cx.tcx, ori_res_did);
         let is_hidden = inherits_doc_hidden(self.cx.tcx, res_did);
 
         // Only inline if requested or if the item would otherwise be stripped.
@@ -256,20 +264,20 @@ fn maybe_inline_local(
                 let prev = mem::replace(&mut self.inlining, true);
                 for &i in m.item_ids {
                     let i = self.cx.tcx.hir().item(i);
-                    self.visit_item(i, None, om, Some(def_id));
+                    self.visit_item_inner(i, None, Some(def_id));
                 }
                 self.inlining = prev;
                 true
             }
             Node::Item(it) if !glob => {
                 let prev = mem::replace(&mut self.inlining, true);
-                self.visit_item(it, renamed, om, Some(def_id));
+                self.visit_item_inner(it, renamed, Some(def_id));
                 self.inlining = prev;
                 true
             }
             Node::ForeignItem(it) if !glob => {
                 let prev = mem::replace(&mut self.inlining, true);
-                self.visit_foreign_item(it, renamed, om);
+                self.visit_foreign_item_inner(it, renamed);
                 self.inlining = prev;
                 true
             }
@@ -279,18 +287,28 @@ fn maybe_inline_local(
         ret
     }
 
-    fn visit_item(
+    #[inline]
+    fn add_to_current_mod(
         &mut self,
         item: &'tcx hir::Item<'_>,
         renamed: Option<Symbol>,
-        om: &mut Module<'tcx>,
         parent_id: Option<LocalDefId>,
     ) {
+        self.modules.last_mut().unwrap().items.push((item, renamed, parent_id))
+    }
+
+    fn visit_item_inner(
+        &mut self,
+        item: &'tcx hir::Item<'_>,
+        renamed: Option<Symbol>,
+        import_id: Option<LocalDefId>,
+    ) -> bool {
         debug!("visiting item {:?}", item);
         let name = renamed.unwrap_or(item.ident.name);
+        let tcx = self.cx.tcx;
 
         let def_id = item.owner_id.to_def_id();
-        let is_pub = self.cx.tcx.visibility(def_id).is_public();
+        let is_pub = tcx.visibility(def_id).is_public();
 
         if is_pub {
             self.store_path(item.owner_id.to_def_id());
@@ -299,8 +317,8 @@ fn visit_item(
         match item.kind {
             hir::ItemKind::ForeignMod { items, .. } => {
                 for item in items {
-                    let item = self.cx.tcx.hir().foreign_item(item.id);
-                    self.visit_foreign_item(item, None, om);
+                    let item = tcx.hir().foreign_item(item.id);
+                    self.visit_foreign_item_inner(item, None);
                 }
             }
             // If we're inlining, skip private items or item reexported as "_".
@@ -315,7 +333,8 @@ fn visit_item(
                         continue;
                     }
 
-                    let attrs = self.cx.tcx.hir().attrs(item.hir_id());
+                    let attrs =
+                        tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(item.owner_id.def_id));
 
                     // If there was a private module in the current path then don't bother inlining
                     // anything as it will probably be stripped anyway.
@@ -333,14 +352,13 @@ fn visit_item(
                             res,
                             ident,
                             is_glob,
-                            om,
                             please_inline,
                         ) {
                             continue;
                         }
                     }
 
-                    om.items.push((item, renamed, parent_id))
+                    self.add_to_current_mod(item, renamed, import_id);
                 }
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
@@ -357,14 +375,14 @@ fn visit_item(
 
                 let def_id = item.owner_id.to_def_id();
                 let is_macro_2_0 = !macro_def.macro_rules;
-                let nonexported = !self.cx.tcx.has_attr(def_id, sym::macro_export);
+                let nonexported = !tcx.has_attr(def_id, sym::macro_export);
 
                 if is_macro_2_0 || nonexported || self.inlining {
-                    om.items.push((item, renamed, None));
+                    self.add_to_current_mod(item, renamed, None);
                 }
             }
             hir::ItemKind::Mod(ref m) => {
-                om.mods.push(self.visit_mod_contents(item.owner_id.def_id, m, name, parent_id));
+                self.enter_mod(item.owner_id.def_id, m, name);
             }
             hir::ItemKind::Fn(..)
             | hir::ItemKind::ExternCrate(..)
@@ -375,33 +393,87 @@ fn visit_item(
             | hir::ItemKind::OpaqueTy(..)
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Trait(..)
-            | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed, parent_id)),
+            | hir::ItemKind::TraitAlias(..) => {
+                self.add_to_current_mod(item, renamed, import_id);
+            }
             hir::ItemKind::Const(..) => {
                 // Underscore constants do not correspond to a nameable item and
                 // so are never useful in documentation.
                 if name != kw::Underscore {
-                    om.items.push((item, renamed, parent_id));
+                    self.add_to_current_mod(item, renamed, import_id);
                 }
             }
             hir::ItemKind::Impl(impl_) => {
                 // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick
                 // them up regardless of where they're located.
                 if !self.inlining && impl_.of_trait.is_none() {
-                    om.items.push((item, None, None));
+                    self.add_to_current_mod(item, None, None);
                 }
             }
         }
+        true
     }
 
-    fn visit_foreign_item(
+    fn visit_foreign_item_inner(
         &mut self,
         item: &'tcx hir::ForeignItem<'_>,
         renamed: Option<Symbol>,
-        om: &mut Module<'tcx>,
     ) {
         // If inlining we only want to include public functions.
         if !self.inlining || self.cx.tcx.visibility(item.owner_id).is_public() {
-            om.foreigns.push((item, renamed));
+            self.modules.last_mut().unwrap().foreigns.push((item, renamed));
+        }
+    }
+
+    /// This method will create a new module and push it onto the "modules stack" then call
+    /// `visit_mod_contents`. Once done, it'll remove it from the "modules stack" and instead
+    /// add into the list of modules of the current module.
+    fn enter_mod(&mut self, id: LocalDefId, m: &'tcx hir::Mod<'tcx>, name: Symbol) {
+        self.modules.push(Module::new(name, id, m.spans.inner_span));
+
+        self.visit_mod_contents(id, m);
+
+        let last = self.modules.pop().unwrap();
+        self.modules.last_mut().unwrap().mods.push(last);
+    }
+}
+
+// We need to implement this visitor so it'll go everywhere and retrieve items we're interested in
+// such as impl blocks in const blocks.
+impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> {
+    type NestedFilter = nested_filter::All;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
+    }
+
+    fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
+        if self.visit_item_inner(i, None, None) {
+            walk_item(self, i);
         }
     }
+
+    fn visit_mod(&mut self, _: &hir::Mod<'tcx>, _: Span, _: hir::HirId) {
+        // Handled in `visit_item_inner`
+    }
+
+    fn visit_use(&mut self, _: &hir::UsePath<'tcx>, _: hir::HirId) {
+        // Handled in `visit_item_inner`
+    }
+
+    fn visit_path(&mut self, _: &hir::Path<'tcx>, _: hir::HirId) {
+        // Handled in `visit_item_inner`
+    }
+
+    fn visit_label(&mut self, _: &rustc_ast::Label) {
+        // Unneeded.
+    }
+
+    fn visit_infer(&mut self, _: &hir::InferArg) {
+        // Unneeded.
+    }
+
+    fn visit_lifetime(&mut self, _: &hir::Lifetime) {
+        // Unneeded.
+    }
 }
index 3c5af6bed9a1a243a693e8e22ee2486bd5b82a6c..82c3bb79e3a19a5164e33819ef81bfc2c984bc56 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3c5af6bed9a1a243a693e8e22ee2486bd5b82a6c
+Subproject commit 82c3bb79e3a19a5164e33819ef81bfc2c984bc56
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 5b2eee7eed72b4894909c5eecbf014ea0b5ad995..9981e4d1ea6ac0992ff21be5514d4230dc77548b 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5b2eee7eed72b4894909c5eecbf014ea0b5ad995
+Subproject commit 9981e4d1ea6ac0992ff21be5514d4230dc77548b
index d58f7547fefb3364f9cae0c308c6bff8d2ca94cf..7978d8cba95412cb3ef9c51b8d1a40ec5b982294 100644 (file)
@@ -13,7 +13,7 @@
 use std::panic::{catch_unwind, AssertUnwindSafe};
 
 use rustc_ast::token::{BinOpToken, Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{Cursor, TokenStream, TokenTree};
+use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
 use rustc_ast::{ast, ptr};
 use rustc_ast_pretty::pprust;
 use rustc_span::{
@@ -736,7 +736,7 @@ fn add_other(&mut self) {
         self.buf.clear();
     }
 
-    fn add_meta_variable(&mut self, iter: &mut Cursor) -> Option<()> {
+    fn add_meta_variable(&mut self, iter: &mut TokenTreeCursor) -> Option<()> {
         match iter.next() {
             Some(TokenTree::Token(
                 Token {
@@ -768,7 +768,7 @@ fn add_repeat(
         &mut self,
         inner: Vec<ParsedMacroArg>,
         delim: Delimiter,
-        iter: &mut Cursor,
+        iter: &mut TokenTreeCursor,
     ) -> Option<()> {
         let mut buffer = String::new();
         let mut first = true;
@@ -1121,7 +1121,7 @@ pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> D
 // Currently we do not attempt to parse any further than that.
 #[derive(new)]
 struct MacroParser {
-    toks: Cursor,
+    toks: TokenTreeCursor,
 }
 
 impl MacroParser {
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 5e587be1f1653f482d6bb3a8678ce14bf847cfda..f1f53a481655ca6e3ec7685527f2c440acec5ff8 100644 (file)
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/const_debuginfo.rs:+1:9: +1:10
           _1 = const 1_u8;                 // scope 0 at $DIR/const_debuginfo.rs:+1:13: +1:16
-          StorageLive(_2);                 // scope 1 at $DIR/const_debuginfo.rs:+2:9: +2:10
           _2 = const 2_u8;                 // scope 1 at $DIR/const_debuginfo.rs:+2:13: +2:16
-          StorageLive(_3);                 // scope 2 at $DIR/const_debuginfo.rs:+3:9: +3:10
           _3 = const 3_u8;                 // scope 2 at $DIR/const_debuginfo.rs:+3:13: +3:16
           StorageLive(_4);                 // scope 3 at $DIR/const_debuginfo.rs:+4:9: +4:12
           StorageLive(_5);                 // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:20
           StorageLive(_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 e085a88b2da8ba155f44730090f1545df43ce64b..ae9ffd519a148ec6efd25eed5dbe487e231ee483 100644 (file)
@@ -18,7 +18,6 @@
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:9: +1:10
           _1 = const 0_i32;                // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:13: +1:14
           StorageLive(_2);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:9: +2:11
 -         _4 = Eq(_1, const 0_i32);        // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
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 e3f5b120a3234d8bb12f2eb2b99fe3199f04422d..22f710387db71d8321606cc4c303f361bfd09a65 100644 (file)
@@ -11,7 +11,6 @@
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/scalar_literal_propagation.rs:+1:9: +1:10
           _1 = const 1_u32;                // scope 0 at $DIR/scalar_literal_propagation.rs:+1:13: +1:14
           StorageLive(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
 -         _2 = consume(_1) -> bb1;         // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
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 bc5083e1ad01a9c9e00b35bf8df741867778348c..3e61869e82f11f2085a133825c7ea62b86d52ed9 100644 (file)
@@ -29,7 +29,7 @@
       }
   
       bb1: {
-          StorageLive(_2);                 // scope 1 at $DIR/cycle.rs:+2:9: +2:10
+-         StorageLive(_2);                 // scope 1 at $DIR/cycle.rs:+2:9: +2:10
           _2 = _1;                         // scope 1 at $DIR/cycle.rs:+2:13: +2:14
 -         StorageLive(_3);                 // scope 2 at $DIR/cycle.rs:+3:9: +3:10
 -         _3 = _2;                         // scope 2 at $DIR/cycle.rs:+3:13: +3:14
index 918817da56ce48b2b2d6dfbd791b5379d2043954..d48b04e2de273887ca85aa141f8812c1a36be817 100644 (file)
@@ -11,7 +11,6 @@ fn f(_1: usize) -> usize {
     }
 
     bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/dead_stores_79191.rs:+1:9: +1:10
         _2 = _1;                         // scope 0 at $DIR/dead_stores_79191.rs:+1:13: +1:14
         _1 = const 5_usize;              // scope 1 at $DIR/dead_stores_79191.rs:+2:5: +2:10
         _1 = _2;                         // scope 1 at $DIR/dead_stores_79191.rs:+3:5: +3:10
index cf21fadd437907823c5a5a63f251e272fa1035e7..727791f50a4ef67b0b15283df8ff7677ebbea1d5 100644 (file)
@@ -11,7 +11,6 @@ fn f(_1: usize) -> usize {
     }
 
     bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/dead_stores_better.rs:+1:9: +1:10
         _2 = _1;                         // scope 0 at $DIR/dead_stores_better.rs:+1:13: +1:14
         _1 = const 5_usize;              // scope 1 at $DIR/dead_stores_better.rs:+2:5: +2:10
         _1 = _2;                         // scope 1 at $DIR/dead_stores_better.rs:+3:5: +3:10
diff --git a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.diff b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.diff
new file mode 100644 (file)
index 0000000..97d0a01
--- /dev/null
@@ -0,0 +1,138 @@
+- // MIR for `main` before CopyProp
++ // MIR for `main` after CopyProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/issue_107511.rs:+0:11: +0:11
+      let mut _1: i32;                     // in scope 0 at $DIR/issue_107511.rs:+1:9: +1:16
+      let mut _3: std::ops::Range<usize>;  // in scope 0 at $DIR/issue_107511.rs:+6:14: +6:24
+      let mut _4: std::ops::Range<usize>;  // in scope 0 at $DIR/issue_107511.rs:+6:14: +6:24
+      let mut _5: usize;                   // in scope 0 at $DIR/issue_107511.rs:+6:17: +6:24
+      let mut _6: &[i32];                  // in scope 0 at $DIR/issue_107511.rs:+6:17: +6:24
+      let mut _7: &[i32; 4];               // in scope 0 at $DIR/issue_107511.rs:+6:17: +6:24
+      let mut _9: ();                      // in scope 0 at $DIR/issue_107511.rs:+0:1: +9:2
+      let _10: ();                         // in scope 0 at $DIR/issue_107511.rs:+6:14: +6:24
+      let mut _11: std::option::Option<usize>; // in scope 0 at $DIR/issue_107511.rs:+6:14: +6:24
+      let mut _12: &mut std::ops::Range<usize>; // in scope 0 at $DIR/issue_107511.rs:+6:14: +6:24
+      let mut _13: &mut std::ops::Range<usize>; // in scope 0 at $DIR/issue_107511.rs:+6:14: +6:24
+      let mut _14: isize;                  // in scope 0 at $DIR/issue_107511.rs:+6:5: +8:6
+      let mut _15: !;                      // in scope 0 at $DIR/issue_107511.rs:+6:5: +8:6
+      let mut _17: i32;                    // in scope 0 at $DIR/issue_107511.rs:+7:16: +7:20
+      let _18: usize;                      // in scope 0 at $DIR/issue_107511.rs:+7:18: +7:19
+      let mut _19: usize;                  // in scope 0 at $DIR/issue_107511.rs:+7:16: +7:20
+      let mut _20: bool;                   // in scope 0 at $DIR/issue_107511.rs:+7:16: +7:20
+      scope 1 {
+          debug sum => _1;                 // in scope 1 at $DIR/issue_107511.rs:+1:9: +1:16
+          let _2: [i32; 4];                // in scope 1 at $DIR/issue_107511.rs:+2:9: +2:10
+          scope 2 {
+              debug a => _2;               // in scope 2 at $DIR/issue_107511.rs:+2:9: +2:10
+              let mut _8: std::ops::Range<usize>; // in scope 2 at $DIR/issue_107511.rs:+6:14: +6:24
+              scope 3 {
+                  debug iter => _8;        // in scope 3 at $DIR/issue_107511.rs:+6:14: +6:24
+                  let _16: usize;          // in scope 3 at $DIR/issue_107511.rs:+6:9: +6:10
+                  scope 4 {
+                      debug i => _16;      // in scope 4 at $DIR/issue_107511.rs:+6:9: +6:10
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/issue_107511.rs:+1:9: +1:16
+          _1 = const 0_i32;                // scope 0 at $DIR/issue_107511.rs:+1:19: +1:20
+          StorageLive(_2);                 // scope 1 at $DIR/issue_107511.rs:+2:9: +2:10
+          _2 = [const 0_i32, const 10_i32, const 20_i32, const 30_i32]; // scope 1 at $DIR/issue_107511.rs:+2:13: +2:28
+          StorageLive(_3);                 // scope 2 at $DIR/issue_107511.rs:+6:14: +6:24
+          StorageLive(_4);                 // scope 2 at $DIR/issue_107511.rs:+6:14: +6:24
+          StorageLive(_5);                 // scope 2 at $DIR/issue_107511.rs:+6:17: +6:24
+          StorageLive(_6);                 // scope 2 at $DIR/issue_107511.rs:+6:17: +6:24
+          StorageLive(_7);                 // scope 2 at $DIR/issue_107511.rs:+6:17: +6:24
+          _7 = &_2;                        // scope 2 at $DIR/issue_107511.rs:+6:17: +6:24
+          _6 = move _7 as &[i32] (Pointer(Unsize)); // scope 2 at $DIR/issue_107511.rs:+6:17: +6:24
+          StorageDead(_7);                 // scope 2 at $DIR/issue_107511.rs:+6:17: +6:18
+          _5 = core::slice::<impl [i32]>::len(move _6) -> bb1; // scope 2 at $DIR/issue_107511.rs:+6:17: +6:24
+                                           // mir::Constant
+                                           // + span: $DIR/issue_107511.rs:10:19: 10:22
+                                           // + literal: Const { ty: for<'a> fn(&'a [i32]) -> usize {core::slice::<impl [i32]>::len}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageDead(_6);                 // scope 2 at $DIR/issue_107511.rs:+6:23: +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
+                                           // + span: $DIR/issue_107511.rs:10:14: 10:24
+                                           // + literal: Const { ty: fn(std::ops::Range<usize>) -> <std::ops::Range<usize> as IntoIterator>::IntoIter {<std::ops::Range<usize> as IntoIterator>::into_iter}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          StorageDead(_4);                 // scope 2 at $DIR/issue_107511.rs:+6:23: +6:24
+          StorageLive(_8);                 // scope 2 at $DIR/issue_107511.rs:+6:14: +6:24
+          _8 = move _3;                    // scope 2 at $DIR/issue_107511.rs:+6:14: +6:24
+          goto -> bb3;                     // scope 3 at $DIR/issue_107511.rs:+6:5: +8:6
+      }
+  
+      bb3: {
+-         StorageLive(_10);                // scope 3 at $DIR/issue_107511.rs:+6:14: +6:24
+          StorageLive(_11);                // scope 3 at $DIR/issue_107511.rs:+6:14: +6:24
+          StorageLive(_12);                // scope 3 at $DIR/issue_107511.rs:+6:14: +6:24
+          StorageLive(_13);                // scope 3 at $DIR/issue_107511.rs:+6:14: +6:24
+          _13 = &mut _8;                   // scope 3 at $DIR/issue_107511.rs:+6:14: +6:24
+          _12 = &mut (*_13);               // scope 3 at $DIR/issue_107511.rs:+6:14: +6:24
+          _11 = <std::ops::Range<usize> as Iterator>::next(move _12) -> bb4; // scope 3 at $DIR/issue_107511.rs:+6:14: +6:24
+                                           // mir::Constant
+                                           // + span: $DIR/issue_107511.rs:10:14: 10:24
+                                           // + literal: Const { ty: for<'a> fn(&'a mut std::ops::Range<usize>) -> Option<<std::ops::Range<usize> as Iterator>::Item> {<std::ops::Range<usize> as Iterator>::next}, val: Value(<ZST>) }
+      }
+  
+      bb4: {
+          StorageDead(_12);                // scope 3 at $DIR/issue_107511.rs:+6:23: +6:24
+          _14 = discriminant(_11);         // scope 3 at $DIR/issue_107511.rs:+6:14: +6:24
+          switchInt(move _14) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 3 at $DIR/issue_107511.rs:+6:14: +6:24
+      }
+  
+      bb5: {
+-         StorageLive(_16);                // scope 3 at $DIR/issue_107511.rs:+6:9: +6:10
+          _16 = ((_11 as Some).0: usize);  // scope 3 at $DIR/issue_107511.rs:+6:9: +6:10
+          StorageLive(_17);                // scope 4 at $DIR/issue_107511.rs:+7:16: +7:20
+-         StorageLive(_18);                // scope 4 at $DIR/issue_107511.rs:+7:18: +7:19
+-         _18 = _16;                       // scope 4 at $DIR/issue_107511.rs:+7:18: +7:19
+          _19 = Len(_2);                   // scope 4 at $DIR/issue_107511.rs:+7:16: +7:20
+-         _20 = Lt(_18, _19);              // scope 4 at $DIR/issue_107511.rs:+7:16: +7:20
+-         assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, _18) -> bb8; // scope 4 at $DIR/issue_107511.rs:+7:16: +7:20
++         _20 = Lt(_16, _19);              // scope 4 at $DIR/issue_107511.rs:+7:16: +7:20
++         assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, _16) -> bb8; // scope 4 at $DIR/issue_107511.rs:+7:16: +7:20
+      }
+  
+      bb6: {
+          unreachable;                     // scope 3 at $DIR/issue_107511.rs:+6:14: +6:24
+      }
+  
+      bb7: {
+          _0 = const ();                   // scope 3 at $DIR/issue_107511.rs:+6:5: +8:6
+          StorageDead(_13);                // scope 3 at $DIR/issue_107511.rs:+8:5: +8:6
+          StorageDead(_11);                // scope 3 at $DIR/issue_107511.rs:+8:5: +8:6
+-         StorageDead(_10);                // scope 3 at $DIR/issue_107511.rs:+8:5: +8:6
+          StorageDead(_8);                 // scope 2 at $DIR/issue_107511.rs:+8:5: +8:6
+          StorageDead(_3);                 // scope 2 at $DIR/issue_107511.rs:+8:5: +8:6
+          StorageDead(_2);                 // scope 1 at $DIR/issue_107511.rs:+9:1: +9:2
+          StorageDead(_1);                 // scope 0 at $DIR/issue_107511.rs:+9:1: +9:2
+          return;                          // scope 0 at $DIR/issue_107511.rs:+9:2: +9:2
+      }
+  
+      bb8: {
+-         _17 = _2[_18];                   // scope 4 at $DIR/issue_107511.rs:+7:16: +7:20
++         _17 = _2[_16];                   // scope 4 at $DIR/issue_107511.rs:+7:16: +7:20
+          _1 = Add(_1, move _17);          // scope 4 at $DIR/issue_107511.rs:+7:9: +7:20
+          StorageDead(_17);                // scope 4 at $DIR/issue_107511.rs:+7:19: +7:20
+-         StorageDead(_18);                // scope 4 at $DIR/issue_107511.rs:+7:20: +7:21
+-         _10 = const ();                  // scope 4 at $DIR/issue_107511.rs:+6:25: +8:6
+-         StorageDead(_16);                // scope 3 at $DIR/issue_107511.rs:+8:5: +8:6
+          StorageDead(_13);                // scope 3 at $DIR/issue_107511.rs:+8:5: +8:6
+          StorageDead(_11);                // scope 3 at $DIR/issue_107511.rs:+8:5: +8:6
+-         StorageDead(_10);                // scope 3 at $DIR/issue_107511.rs:+8:5: +8:6
+-         _9 = const ();                   // scope 3 at $DIR/issue_107511.rs:+6:5: +8:6
+          goto -> bb3;                     // scope 3 at $DIR/issue_107511.rs:+6:5: +8:6
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/issue_107511.rs b/tests/mir-opt/copy-prop/issue_107511.rs
new file mode 100644 (file)
index 0000000..d593f28
--- /dev/null
@@ -0,0 +1,13 @@
+// unit-test: CopyProp
+
+// EMIT_MIR issue_107511.main.CopyProp.diff
+fn main() {
+    let mut sum = 0;
+    let a = [0, 10, 20, 30];
+
+    // `i` is assigned in a loop. Only removing its `StorageDead` would mean that
+    // execution sees repeated `StorageLive`. This would be UB.
+    for i in 0..a.len() {
+        sum += a[i];
+    }
+}
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 6870d7d6c45b457b8459dce4a63f514fdb4cbdc8..9c3f87f47c12c0ebab94e7691ada61e6f4ca4e79 100644 (file)
@@ -16,9 +16,7 @@
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
           _1 = const u8::MAX;              // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
-          StorageLive(_2);                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
           _2 = const 1_u8;                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
           _5 = CheckedAdd(const u8::MAX, const 1_u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
           assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> bb1; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
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 df9f8dcf1a407b7496b9f719db0d88d374162b5c..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
       }
   
@@ -79,7 +85,6 @@
       }
   
       bb6: {
-          StorageLive(_10);                // scope 3 at $DIR/funky_arms.rs:+13:17: +13:26
           _10 = ((_7 as Some).0: usize);   // scope 3 at $DIR/funky_arms.rs:+13:17: +13:26
           StorageLive(_11);                // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46
           _11 = &mut (*_1);                // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46
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 30bf2c0684e52525ba75d3da0232559318bd75f4..002392c5cf81a24c59eb8b600647cda96a1427a9 100644 (file)
@@ -33,7 +33,6 @@
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65
           StorageLive(_3);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:58
-          StorageLive(_4);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:17
           StorageLive(_12);                // scope 2 at $DIR/issue_101973.rs:7:12: 7:27
           StorageLive(_13);                // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
           _14 = CheckedShr(_1, const 0_i32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
@@ -63,7 +62,6 @@
           StorageDead(_13);                // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
           _4 = BitOr(const 0_u32, move _12); // scope 2 at $DIR/issue_101973.rs:7:5: 7:27
           StorageDead(_12);                // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
-          StorageLive(_6);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
           StorageLive(_7);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
           StorageLive(_8);                 // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
           _10 = CheckedShr(_1, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
index c14780052fb091f257fefbd178c0c05357f2c7c7..cc4f7cc06991f6b77ce66f0cee3f33c8789ede9e 100644 (file)
@@ -29,7 +29,6 @@
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/issue_76432.rs:+1:9: +1:10
-          StorageLive(_4);                 // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
           StorageLive(_5);                 // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29
           _5 = [_1, _1, _1];               // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29
           _4 = &_5;                        // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
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
       }
   
index 35ffc4963cb63b4f8d707e2d633ceca9a720548e..b700adfb105b041ff1401f8de61169c5842846cf 100644 (file)
@@ -10,7 +10,6 @@
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/simplify_match.rs:+1:17: +1:18
           _2 = const false;                // scope 0 at $DIR/simplify_match.rs:+1:21: +1:26
 -         switchInt(_2) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
 +         switchInt(const false) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
index d1f6fd97dc7c6cf58349fe1e087562b84bb12af5..da6389676f0d47967a061b36841635925825d333 100644 (file)
       }
   
       bb0: {
-          StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+-         StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
           _25 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
           _3 = &((*_25).0: usize);         // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
-          StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+-         StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
           _26 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
           _4 = &((*_26).1: usize);         // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
-          StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+-         StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
           _27 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
           _5 = &((*_27).2: usize);         // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
-          StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+-         StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
           _28 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
           _6 = &((*_28).3: usize);         // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
           StorageLive(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
index 259cd4118960884844bdfedf7e746a4c09ee23bf..294c3272f4f1020b92e7b6da63ae7e8999660947 100644 (file)
       }
   
       bb0: {
-          StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
           _25 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
           _3 = &((*_25).0: usize);         // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
-          StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
           _26 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
           _4 = &((*_26).1: usize);         // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
-          StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
           _27 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
           _5 = &((*_27).2: usize);         // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
-          StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
           _28 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
           _6 = &((*_28).3: usize);         // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
 -         StorageLive(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
index c3b8e7d2eba256530fe2bff824cb42f06fe898fd..5e4bdbdfa2e2f9683e0b5206db7181c30c81db94 100644 (file)
       }
   
       bb0: {
-          StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+-         StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
           _21 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
           _3 = ((*_21).0: usize);          // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
-          StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+-         StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
           _22 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
           _4 = ((*_22).1: usize);          // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
-          StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+-         StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
           _23 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
           _5 = ((*_23).2: usize);          // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
-          StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+-         StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
           _24 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
           _6 = ((*_24).3: usize);          // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
           StorageLive(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
index a43e84d29c7add13d800b436f50349c55987a8ee..45af6600cd4e8ed268756a700123dbe015795fea 100644 (file)
       }
   
       bb0: {
-          StorageLive(_3);                 // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
           _13 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
           _3 = ((*_13).0: usize);          // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
-          StorageLive(_4);                 // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
           _14 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
           _4 = ((*_14).1: usize);          // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
-          StorageLive(_5);                 // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
           _15 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
           _5 = ((*_15).2: usize);          // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
-          StorageLive(_6);                 // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
           _16 = deref_copy (*_2);          // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
           _6 = ((*_16).3: usize);          // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
 -         StorageLive(_7);                 // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
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 7c67d2abcf7c37ccf1e0997d8550779a58c4d52f..b9cc1057513d08670528189998ac5af3ed236710 100644 (file)
@@ -26,49 +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: {
-        StorageLive(_5);                 // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
         _5 = move ((_1 as Err).0: E);    // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
-        Deinit(_2);                      // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
-        ((_2 as Break).0: E) = move _5;  // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
-        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: {
-        StorageLive(_4);                 // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
         _4 = move ((_1 as Ok).0: T);     // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
-        Deinit(_2);                      // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
-        ((_2 as Continue).0: T) = move _4; // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
-        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: {
-        StorageLive(_8);                 // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
+        _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: {
-        StorageLive(_7);                 // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
+    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 4a838e140262e76e51434fcb2f51f5bf4a743ea1..d88ae5ac93eba8504d22de3bd38b486dadae2ef4 100644 (file)
@@ -19,11 +19,8 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb1: {
-        StorageLive(_4);                 // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
         _4 = move ((_1 as Err).0: E);    // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
-        Deinit(_0);                      // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
-        ((_0 as Err).0: E) = move _4;    // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
-        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,11 +29,8 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb3: {
-        StorageLive(_3);                 // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
         _3 = move ((_1 as Ok).0: T);     // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
-        Deinit(_0);                      // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
-        ((_0 as Ok).0: T) = move _3;     // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
-        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 4b1e04234c870594bcaaf458bb9b2fbe39507c8c..939da186fbcdb2dcac7b1f6b7f5dca4d7c280f32 100644 (file)
@@ -1,12 +1,10 @@
-// check-pass
 // normalize-stderr-test: "`.*`" -> "`DEF_ID`"
 // normalize-stdout-test: "`.*`" -> "`DEF_ID`"
 // edition:2018
 
 pub async fn f() -> impl std::fmt::Debug {
-    // rustdoc doesn't care that this is infinitely sized
     #[derive(Debug)]
-    enum E {
+    enum E { //~ ERROR
         This(E),
         Unit,
     }
diff --git a/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr b/tests/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr
new file mode 100644 (file)
index 0000000..aff7402
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0072]: recursive type `DEF_ID` has infinite size
+  --> $DIR/infinite-recursive-type-impl-trait-return.rs:7:5
+   |
+LL |     enum E {
+   |     ^^^^^^
+LL |         This(E),
+   |              - recursive without indirection
+   |
+help: insert some indirection (e.g., a `DEF_ID`) to break the cycle
+   |
+LL |         This(Box<E>),
+   |              ++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `DEF_ID`.
index ac79582fb3f0df48e75c11cc1101e0d9f99ac5bc..ac51725749867cea7f7b979839320140378480d3 100644 (file)
@@ -1,8 +1,5 @@
-// check-pass
-
 fn f() -> impl Sized {
-    // rustdoc doesn't care that this is infinitely sized
-    enum E {
+    enum E { //~ ERROR
         V(E),
     }
     unimplemented!()
diff --git a/tests/rustdoc-ui/infinite-recursive-type-impl-trait.stderr b/tests/rustdoc-ui/infinite-recursive-type-impl-trait.stderr
new file mode 100644 (file)
index 0000000..a61577b
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0072]: recursive type `f::E` has infinite size
+  --> $DIR/infinite-recursive-type-impl-trait.rs:2:5
+   |
+LL |     enum E {
+   |     ^^^^^^
+LL |         V(E),
+   |           - recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
+   |
+LL |         V(Box<E>),
+   |           ++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0072`.
index 3db344af67439c5c877b2d532dfc538eea9623d5..70bcbcb6ff44ae3d5851a71b6f729950a41c4795 100644 (file)
@@ -77,7 +77,7 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T }
 
 impl Foo {
     // @has async_fn/struct.Foo.html
-    // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+    // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar ) -> impl Iterator<Item = &usize>'
     pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
     // taken from `tokio` as an example of a method that was particularly bad before
     // @has - '//*[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
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 ade70bbe80d923a1b5f02467eecd13e6e4b5916e..cbda095424b7d1536c6ea359a48c86b76c11ecee 100644 (file)
@@ -31,7 +31,7 @@ impl Trait<{1 + 2}> for u8 {}
 impl<const N: usize> Trait<N> for [u8; N] {}
 
 // @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \
-//      'pub struct Foo<const N: usize>where u8: Trait<N>'
+//      'pub struct Foo<const N: usize> where u8: Trait<N>'
 pub struct Foo<const N: usize> where u8: Trait<N>;
 // @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar<T, const N: usize>(_)'
 pub struct Bar<T, const N: usize>([T; N]);
index 02b51b3446195711319d83369a393c2d7d5ac452..d73393633f3b8c97b1ea04eee609a46ce59a4d50 100644 (file)
@@ -1,7 +1,23 @@
 <code>pub trait Write {
-    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;;
+    // Required methods
+    fn <a href="#tymethod.poll_write" class="fn">poll_write</a>(
+        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;,
+        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;,
+        buf: &amp;mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]
+    ) -&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>(
+        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;,
+        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;
+    ) -&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>(
+        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;,
+        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;
+    ) -&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;;
 
-    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; { ... }
+    // Provided method
+    fn <a href="#method.poll_write_vectored" class="fn">poll_write_vectored</a>(
+        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;,
+        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;,
+        bufs: &amp;[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]
+    ) -&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
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 bcead3115fef42f58086ee604ba1017b2230f0f4..7ab82bb582965909480eee1defb38a96fe149ec6 100644 (file)
@@ -2,7 +2,7 @@
 
 // @has foo/trait.LendingIterator.html
 pub trait LendingIterator {
-    // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a"
+    // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a"
     type Item<'a> where Self: 'a;
 
     // @has - '//*[@id="tymethod.next"]//h4[@class="code-header"]' \
@@ -23,7 +23,7 @@ fn next<'a>(&self) -> () {}
 pub struct Infinite<T>(T);
 
 // @has foo/trait.LendingIterator.html
-// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a = &'a T"
+// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a = &'a T"
 impl<T> LendingIterator for Infinite<T> {
     type Item<'a> where Self: 'a = &'a T;
 
diff --git a/tests/rustdoc/hidden-private.rs b/tests/rustdoc/hidden-private.rs
new file mode 100644 (file)
index 0000000..834ba52
--- /dev/null
@@ -0,0 +1,50 @@
+// This is a regression test for <https://github.com/rust-lang/rust/issues/106373>.
+// It ensures that the items in the `doc(hidden)` const block don't show up in the
+// generated docs.
+
+// compile-flags: --document-private-items
+
+#![crate_name = "foo"]
+
+// @has 'foo/index.html'
+// @count - '//*[@class="item-table"]//a[@class="struct"]' 2
+// @count - '//*[@class="item-table"]//a[@class="trait"]' 1
+// @count - '//*[@class="item-table"]//a[@class="macro"]' 0
+#[doc(hidden)]
+const _: () = {
+    macro_rules! stry {
+        () => {};
+    }
+
+    struct ShouldBeHidden;
+
+    // @has 'foo/struct.Foo.html'
+    // @!has - '//*[@class="code-header"]' 'impl Bar for Foo'
+    #[doc(hidden)]
+    impl Bar for Foo {
+        fn bar(&self) {
+            struct SHouldAlsoBeHidden;
+        }
+    }
+
+    // @has 'foo/struct.Private.html'
+    // @has - '//*[@id="impl-Bar-for-Private"]/*[@class="code-header"]' 'impl Bar for Private'
+    // @has - '//*[@id="method.bar"]/*[@class="code-header"]' 'fn bar(&self)'
+    impl Bar for Private {
+        fn bar(&self) {}
+    }
+
+    // @has - '//*[@id="impl-Private"]/*[@class="code-header"]' 'impl Private'
+    // @has - '//*[@id="method.tralala"]/*[@class="code-header"]' 'fn tralala()'
+    impl Private {
+        fn tralala() {}
+    }
+};
+
+
+struct Private;
+pub struct Foo;
+
+pub trait Bar {
+    fn bar(&self);
+}
diff --git a/tests/rustdoc/impl-in-const-block.rs b/tests/rustdoc/impl-in-const-block.rs
new file mode 100644 (file)
index 0000000..b44e713
--- /dev/null
@@ -0,0 +1,43 @@
+// Regression test for #83026.
+// The goal of this test is to ensure that impl blocks inside
+// const expressions are documented as well.
+
+#![crate_name = "foo"]
+
+// @has 'foo/struct.A.html'
+// @has - '//*[@id="method.new"]/*[@class="code-header"]' 'pub fn new() -> A'
+// @has - '//*[@id="method.bar"]/*[@class="code-header"]' 'pub fn bar(&self)'
+// @has - '//*[@id="method.woo"]/*[@class="code-header"]' 'pub fn woo(&self)'
+// @has - '//*[@id="method.yoo"]/*[@class="code-header"]' 'pub fn yoo()'
+// @has - '//*[@id="method.yuu"]/*[@class="code-header"]' 'pub fn yuu()'
+pub struct A;
+
+const _: () = {
+    impl A {
+        const FOO: () = {
+            impl A {
+                pub fn woo(&self) {}
+            }
+        };
+
+        pub fn new() -> A {
+            A
+        }
+    }
+};
+pub const X: () = {
+    impl A {
+        pub fn bar(&self) {}
+    }
+};
+
+fn foo() {
+    impl A {
+        pub fn yoo() {}
+    }
+    const _: () = {
+        impl A {
+            pub fn yuu() {}
+        }
+    };
+}
index 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 7d810ab4813720120026e9f21a4c8fd0f15d0561..b6a1552bc00caccca655c5439f64878f9567d8d4 100644 (file)
@@ -11,7 +11,7 @@
 // @has impl_trait/fn.func2.html
 // @has - '//pre[@class="rust item-decl"]' "func2<T>("
 // @has - '//pre[@class="rust item-decl"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>,"
-// @has - '//pre[@class="rust item-decl"]' "_y: impl Iterator<Item = u8>)"
+// @has - '//pre[@class="rust item-decl"]' "_y: impl Iterator<Item = u8> )"
 // @!has - '//pre[@class="rust item-decl"]' 'where'
 pub use impl_trait_aux::func2;
 
index 91b67757453d2e788343eb82a15fa1d26313d309..4184086f622abaff7f57fb211360c358ccfe15c8 100644 (file)
@@ -2,5 +2,5 @@
 
 pub trait Bar {}
 
-// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T)where T: Bar;'
+// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T) where T: Bar;'
 pub struct Foo<T>(pub T) where T: Bar;
index 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 e3a14c7a74a0024465899c1c1c85591e447efd8a..5b7a76e1a7739403e4f66a8bda012e8f9413eb6d 100644 (file)
@@ -9,9 +9,10 @@ pub trait Foo {}
 // @has redirect/index.html
 // @has - '//code' 'pub use reexp_stripped::Bar'
 // @has - '//code/a' 'Bar'
+// @has - '//a[@href="../reexp_stripped/hidden/struct.Bar.html"]' 'Bar'
 // @has reexp_stripped/hidden/struct.Bar.html
-// @has - '//p/a' '../../reexp_stripped/struct.Bar.html'
 // @has 'reexp_stripped/struct.Bar.html'
+// @has - '//a[@href="struct.Bar.html"]' 'Bar'
 #[doc(no_inline)]
 pub use reexp_stripped::Bar;
 impl Foo for Bar {}
index 84ea4ad2c9ef30ea8fbb08b948661821ce29cbbe..571d7f06fdc62e401f5b5c161b9a7f79247f4e44 100644 (file)
@@ -98,7 +98,7 @@ pub mod inner {
         pub use reexports::foo;
         // @has 'foo/outer/inner/fn.foo_crate.html' '//pre[@class="rust item-decl"]' 'pub(crate) fn foo_crate()'
         pub(crate) use reexports::foo_crate;
-        // @has 'foo/outer/inner/fn.foo_super.html' '//pre[@class="rust item-decl"]' 'pub(in outer) fn foo_super()'
+        // @has 'foo/outer/inner/fn.foo_super.html' '//pre[@class="rust item-decl"]' 'pub(in outer) fn foo_super( )'
         pub(super) use::reexports::foo_super;
         // @!has 'foo/outer/inner/fn.foo_self.html'
         pub(self) use reexports::foo_self;
index 6f151f2328e4f69878f096086df403ef0610e6fa..ef4294c8f76d3c397131c17862c091e2de5f19f8 100644 (file)
@@ -1 +1,3 @@
-<pre class="rust item-decl"><code>pub struct Simd&lt;T&gt;(_)<br /><span class="where">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre>
\ No newline at end of file
+<pre class="rust item-decl"><code>pub struct Simd&lt;T&gt;(_)
+<span class="where">where
+         T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre>
\ No newline at end of file
index 11df902f3720f7d6cc9c87d72fd1163b3bacb2b8..e8ab061e679dd09f7f39d99ac6a5d397fa770da6 100644 (file)
@@ -1,8 +1,13 @@
 <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;
+       <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)
+       <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;
+       <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)
+       <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,
+             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..8b8a126e89dd524c1364280c2f97445332bd1a98 100644 (file)
@@ -4,7 +4,7 @@
 
 pub trait MyTrait { fn dummy(&self) { } }
 
-// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_)where A: MyTrait"
+// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait"
 pub struct Alpha<A>(A) where A: MyTrait;
 // @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B>where B: MyTrait"
 pub trait Bravo<B> where B: MyTrait { fn get(&self, B: B); }
@@ -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 904d461103617eefdc2fdc39f3db10c064c440cf..20b60b68e88cfed63dc3f9deb4a1c59fc19f2488 100644 (file)
@@ -1,4 +1,5 @@
-<pre class="rust item-decl"><code>pub enum Cow&lt;'a, B&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub enum Cow&lt;'a, B&gt;<span class="where fmt-newline">where
+    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
     Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a B</a>),
     Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
 }</code></pre>
\ No newline at end of file
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 54faee9e4052bc0da60e9db96d78e6fbd5a4bf6d..948ddc499da8ad9c8c2b24fc43eb1ab3ba87d1ee 100644 (file)
@@ -1,4 +1,5 @@
-<pre class="rust item-decl"><code>pub struct Struct&lt;'a, B&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub struct Struct&lt;'a, B&gt;<span class="where fmt-newline">where
+    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
     pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a B</a>,
     pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
 }</code></pre>
\ 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..0928b48e6b64cf9b9b1d1e8f998e32532cde13ac 100644 (file)
@@ -1,6 +1,8 @@
-<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>{
+<pre class="rust item-decl"><code>pub trait ToOwned&lt;T&gt;<span class="where fmt-newline">where
+    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 03a26280ba2cf9f5eb27e848f8651138227c8413..38b6cb8b5c6131ddc25fac5f75acd81eb9eb0550 100644 (file)
@@ -1,3 +1,4 @@
-<pre class="rust item-decl"><code>pub union Union&lt;'a, B&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub union Union&lt;'a, B&gt;<span class="where fmt-newline">where
+    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
     /* private fields */
 }</code></pre>
\ 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 65d9601e78ab6980d05557915901a44ad72abfd9..07f95d13937b47d246017b1a0aa7f5f8f555b24d 100644 (file)
@@ -799,3 +799,11 @@ struct SuggestionStyleGood {
     #[suggestion(code = "", style = "hidden")]
     sub: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(compiletest_example)]
+struct SuggestionOnVec {
+    #[suggestion(suggestion, code = "")]
+    //~^ ERROR `#[suggestion(...)]` is not a valid attribute
+    sub: Vec<Span>,
+}
index 13e806a434f637f9e4bb2ca8efec71b06f922ef4..61806c80efc0b8195c10a59153bb33fa439f8b37 100644 (file)
@@ -589,6 +589,16 @@ error: `code = "..."`/`code(...)` must contain only string literals
 LL |     #[suggestion(code = 3)]
    |                  ^^^^^^^^
 
+error: `#[suggestion(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:806:5
+   |
+LL |     #[suggestion(suggestion, code = "")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[suggestion(...)]` applied to `Vec` field is ambiguous
+   = help: to show a suggestion consisting of multiple parts, use a `Subdiagnostic` annotated with `#[multipart_suggestion(...)]`
+   = help: to show a variable set of suggestions, use a `Vec` of `Subdiagnostic`s annotated with `#[suggestion(...)]`
+
 error: cannot find attribute `nonsense` in this scope
   --> $DIR/diagnostic-derive.rs:55:3
    |
@@ -660,7 +670,7 @@ note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
   --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC
    = note: this error originates in the derive macro `Diagnostic` which comes from the expansion of the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 83 previous errors
+error: aborting due to 84 previous errors
 
 Some errors have detailed explanations: E0277, E0425.
 For more information about an error, try `rustc --explain E0277`.
index 61ac456a6b649dc9bfe55a9b94bc15fdb604afe4..09ad69649098342dc26b2da15f462e77c09f8347 100644 (file)
@@ -798,3 +798,13 @@ struct SuggestionStyleInvalid4 {
     #[primary_span]
     sub: Span,
 }
+
+#[derive(Subdiagnostic)]
+#[suggestion(parse_add_paren, code = "")]
+//~^ ERROR suggestion without `#[primary_span]` field
+struct PrimarySpanOnVec {
+    #[primary_span]
+    //~^ ERROR `#[primary_span]` is not a valid attribute
+    //~| NOTE there must be exactly one primary span
+    sub: Vec<Span>,
+}
index b594fa6cde1e454e54600396904b3985c5624c68..f9d1a63031d7cceb84c5093304e523d8a9b6fcc1 100644 (file)
@@ -501,6 +501,27 @@ error: `#[suggestion(style(...))]` is not a valid attribute
 LL | #[suggestion(parse_add_paren, code = "", style("foo"))]
    |                                          ^^^^^^^^^^^^
 
+error: `#[primary_span]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:806:5
+   |
+LL |     #[primary_span]
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: there must be exactly one primary span
+   = help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead
+
+error: suggestion without `#[primary_span]` field
+  --> $DIR/subdiagnostic-derive.rs:803:1
+   |
+LL | / #[suggestion(parse_add_paren, code = "")]
+LL | |
+LL | | struct PrimarySpanOnVec {
+LL | |     #[primary_span]
+...  |
+LL | |     sub: Vec<Span>,
+LL | | }
+   | |_^
+
 error: cannot find attribute `foo` in this scope
   --> $DIR/subdiagnostic-derive.rs:63:3
    |
@@ -561,6 +582,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
 LL | #[label(slug)]
    |         ^^^^ not found in `rustc_errors::fluent`
 
-error: aborting due to 79 previous errors
+error: aborting due to 81 previous errors
 
 For more information about this error, try `rustc --explain E0425`.
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
 
index 627bf05bba2d9c77110d0f7b00af849089c8b5d1..8e2d42c8f138cff4bfb013fb22da8d3e96d44a58 100644 (file)
@@ -6,11 +6,6 @@ LL |         take_u32(x)
    |         |
    |         arguments to this function are incorrect
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/dont-suggest-missing-await.rs:7:24
-   |
-LL | async fn make_u32() -> u32 {
-   |                        ^^^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `u32`
            found opaque type `impl Future<Output = u32>`
 note: function defined here
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
diff --git a/tests/ui/async-await/future-sizes/future-as-arg.rs b/tests/ui/async-await/future-sizes/future-as-arg.rs
new file mode 100644 (file)
index 0000000..93c69b0
--- /dev/null
@@ -0,0 +1,16 @@
+// edition: 2021
+// run-pass
+
+async fn test(_arg: [u8; 16]) {}
+
+async fn use_future(fut: impl std::future::Future<Output = ()>) {
+    fut.await
+}
+
+fn main() {
+    let actual = std::mem::size_of_val(
+        &use_future(use_future(use_future(use_future(use_future(test([0; 16])))))));
+    // Not using an exact number in case it slightly changes over different commits
+    let expected = 550;
+    assert!(actual > expected, "expected: >{expected}, actual: {actual}");
+}
diff --git a/tests/ui/async-await/future-sizes/large-arg.rs b/tests/ui/async-await/future-sizes/large-arg.rs
new file mode 100644 (file)
index 0000000..7e7ff9d
--- /dev/null
@@ -0,0 +1,18 @@
+// compile-flags: -Z print-type-sizes --crate-type=lib
+// edition: 2021
+// build-pass
+// ignore-pass
+
+pub async fn test() {
+    let _ = a([0u8; 1024]).await;
+}
+
+pub async fn a<T>(t: T) -> T {
+    b(t).await
+}
+async fn b<T>(t: T) -> T {
+    c(t).await
+}
+async fn c<T>(t: T) -> T {
+    t
+}
diff --git a/tests/ui/async-await/future-sizes/large-arg.stdout b/tests/ui/async-await/future-sizes/large-arg.stdout
new file mode 100644 (file)
index 0000000..91db4b1
--- /dev/null
@@ -0,0 +1,60 @@
+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 `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 `Returned`: 1024 bytes
+print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Panicked`: 1024 bytes
+print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/large-arg.rs:10:30: 12:2]>`: 3075 bytes, alignment: 1 bytes
+print-type-size     field `.value`: 3075 bytes
+print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/large-arg.rs:10:30: 12:2]>`: 3075 bytes, alignment: 1 bytes
+print-type-size     variant `MaybeUninit`: 3075 bytes
+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 `Returned`: 1024 bytes
+print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Panicked`: 1024 bytes
+print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/large-arg.rs:13:26: 15:2]>`: 2050 bytes, alignment: 1 bytes
+print-type-size     field `.value`: 2050 bytes
+print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/large-arg.rs:13:26: 15:2]>`: 2050 bytes, alignment: 1 bytes
+print-type-size     variant `MaybeUninit`: 2050 bytes
+print-type-size         field `.uninit`: 0 bytes
+print-type-size         field `.value`: 2050 bytes
+print-type-size type: `[async fn body@$DIR/large-arg.rs:16:26: 18:2]`: 1025 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 `Returned`: 1024 bytes
+print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Panicked`: 1024 bytes
+print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/large-arg.rs:16:26: 18:2]>`: 1025 bytes, alignment: 1 bytes
+print-type-size     field `.value`: 1025 bytes
+print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/large-arg.rs:16:26: 18:2]>`: 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: `std::task::Poll<[u8; 1024]>`: 1025 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Ready`: 1024 bytes
+print-type-size         field `.0`: 1024 bytes
+print-type-size     variant `Pending`: 0 bytes
index 963c6ba57adf89448eac3463e72257edc5a0cbd1..9fdb1ce47d7bae8db1a1a042e9dd5e378140f399 100644 (file)
@@ -21,16 +21,6 @@ LL |     fun(one(), two());
    |     |
    |     arguments to this function are incorrect
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/generator-desc.rs:5:16
-   |
-LL | async fn one() {}
-   |                ^ checked the `Output` of this `async fn`, expected opaque type
-note: while checking the return type of the `async fn`
-  --> $DIR/generator-desc.rs:6:16
-   |
-LL | async fn two() {}
-   |                ^ checked the `Output` of this `async fn`, found opaque type
    = note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:5:16>)
               found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:6:16>)
    = help: consider `await`ing on both `Future`s
index 3cde5cca3c3cdddda0dbd6b2b1f88accb40eae5e..9c4acbe0a5bf735857cd288d03589f97810518bd 100644 (file)
@@ -54,9 +54,6 @@ async fn struct_() -> Struct {
 }
 
 async fn tuple() -> Tuple {
-    //~^ NOTE checked the `Output` of this `async fn`, expected opaque type
-    //~| NOTE while checking the return type of the `async fn`
-    //~| NOTE in this expansion of desugaring of `async` block or function
     Tuple(1i32)
 }
 
index 5a7316edd01f55ba5bca0df7e5c1a524a68db570..b25b29bf50c174fd18b5db994a8b6bd8a6d808a9 100644 (file)
@@ -11,7 +11,7 @@ LL |     foo().await?;
    |          ++++++
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/issue-61076.rs:65:5
+  --> $DIR/issue-61076.rs:62:5
    |
 LL |     t?;
    |     ^^ the `?` operator cannot be applied to type `T`
@@ -23,7 +23,7 @@ LL |     t.await?;
    |      ++++++
 
 error[E0609]: no field `0` on type `impl Future<Output = Tuple>`
-  --> $DIR/issue-61076.rs:74:26
+  --> $DIR/issue-61076.rs:71:26
    |
 LL |     let _: i32 = tuple().0;
    |                          ^ field not available in `impl Future`, but it is available in its `Output`
@@ -34,7 +34,7 @@ LL |     let _: i32 = tuple().await.0;
    |                         ++++++
 
 error[E0609]: no field `a` on type `impl Future<Output = Struct>`
-  --> $DIR/issue-61076.rs:78:28
+  --> $DIR/issue-61076.rs:75:28
    |
 LL |     let _: i32 = struct_().a;
    |                            ^ field not available in `impl Future`, but it is available in its `Output`
@@ -45,7 +45,7 @@ LL |     let _: i32 = struct_().await.a;
    |                           ++++++
 
 error[E0599]: no method named `method` found for opaque type `impl Future<Output = Struct>` in the current scope
-  --> $DIR/issue-61076.rs:82:15
+  --> $DIR/issue-61076.rs:79:15
    |
 LL |     struct_().method();
    |               ^^^^^^ method not found in `impl Future<Output = Struct>`
@@ -56,7 +56,7 @@ LL |     struct_().await.method();
    |               ++++++
 
 error[E0308]: mismatched types
-  --> $DIR/issue-61076.rs:91:9
+  --> $DIR/issue-61076.rs:88:9
    |
 LL |     match tuple() {
    |           ------- this expression has type `impl Future<Output = Tuple>`
@@ -64,11 +64,6 @@ LL |
 LL |         Tuple(_) => {}
    |         ^^^^^^^^ expected opaque type, found `Tuple`
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/issue-61076.rs:56:21
-   |
-LL | async fn tuple() -> Tuple {
-   |                     ^^^^^ checked the `Output` of this `async fn`, expected opaque type
    = note: expected opaque type `impl Future<Output = Tuple>`
                    found struct `Tuple`
 help: consider `await`ing on the `Future`
index 08ea5bdc574fa8551ef2837986f14d9545b98f0d..4c5dfeed9ba5c6e87992d40a0b9bb8350e9f56b3 100644 (file)
@@ -4,11 +4,6 @@ error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Futu
 LL |         StructAsync { callback }.await;
    |                       ^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found opaque type
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/issue-98634.rs:24:21
-   |
-LL | async fn callback() {}
-   |                     ^ checked the `Output` of this `async fn`, found opaque type
    = note:   expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
            found opaque type `impl Future<Output = ()>`
 note: required by a bound in `StructAsync`
@@ -23,11 +18,6 @@ error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Futu
 LL |         StructAsync { callback }.await;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found opaque type
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/issue-98634.rs:24:21
-   |
-LL | async fn callback() {}
-   |                     ^ checked the `Output` of this `async fn`, found opaque type
    = note:   expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
            found opaque type `impl Future<Output = ()>`
 note: required by a bound in `StructAsync`
@@ -42,11 +32,6 @@ error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Futu
 LL |         StructAsync { callback }.await;
    |                                 ^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found opaque type
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/issue-98634.rs:24:21
-   |
-LL | async fn callback() {}
-   |                     ^ checked the `Output` of this `async fn`, found opaque type
    = note:   expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
            found opaque type `impl Future<Output = ()>`
 note: required by a bound in `StructAsync`
index eef711910a1a08fbef8b3ba8455f37754111d814..ebb80f6e07e74f21d7271e00cae744cbf90ea390 100644 (file)
@@ -8,11 +8,6 @@ LL |     std::mem::size_of_val(foo());
    |     |                     help: consider borrowing here: `&foo()`
    |     arguments to this function are incorrect
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/issue-102206.rs:3:16
-   |
-LL | async fn foo() {}
-   |                ^ checked the `Output` of this `async fn`, found opaque type
    = note: expected reference `&_`
             found opaque type `impl Future<Output = ()>`
 note: function defined here
index c5bd520aaea0d98c95938cb75ceb05288cdc19cc..71c228958f6fd8933a4d68375d1d474bebae12cf 100644 (file)
@@ -28,8 +28,8 @@ note: ...which requires const checking `x`...
    |
 LL | pub const async fn x() {}
    | ^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
-   = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
+   = note: ...which requires computing whether `x::{opaque#0}` is freeze...
+   = note: ...which requires evaluating trait selection obligation `x::{opaque#0}: core::marker::Freeze`...
    = note: ...which again requires computing type of `x::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in top-level module
   --> $DIR/no-const-async.rs:4:1
index a5958baffbaf72719eb8ba87c6f3f17163c2ea4b..e47325cb4aeaec6fcf5f3291a4d93fa0c30c8b74 100644 (file)
@@ -6,11 +6,6 @@ LL |         take_u32(x)
    |         |
    |         arguments to this function are incorrect
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/suggest-missing-await-closure.rs:8:24
-   |
-LL | async fn make_u32() -> u32 {
-   |                        ^^^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `u32`
            found opaque type `impl Future<Output = u32>`
 note: function defined here
index 2db0666f1ae6847ed4c8c292b160b7ae9198a103..4ed0272ac1a127b7ebd9b0c08948541ddfa21afa 100644 (file)
@@ -6,11 +6,6 @@ LL |     take_u32(x)
    |     |
    |     arguments to this function are incorrect
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/suggest-missing-await.rs:5:24
-   |
-LL | async fn make_u32() -> u32 {
-   |                        ^^^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `u32`
            found opaque type `impl Future<Output = u32>`
 note: function defined here
@@ -29,11 +24,6 @@ error[E0308]: mismatched types
 LL |     dummy()
    |     ^^^^^^^ expected `()`, found opaque type
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/suggest-missing-await.rs:18:18
-   |
-LL | async fn dummy() {}
-   |                  ^ checked the `Output` of this `async fn`, found opaque type
    = note: expected unit type `()`
             found opaque type `impl Future<Output = ()>`
 help: consider `await`ing on the `Future`
@@ -60,11 +50,6 @@ LL | |
 LL | |     };
    | |_____- `if` and `else` have incompatible types
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/suggest-missing-await.rs:18:18
-   |
-LL | async fn dummy() {}
-   |                  ^ checked the `Output` of this `async fn`, expected opaque type
    = note: expected opaque type `impl Future<Output = ()>`
                 found unit type `()`
 help: consider `await`ing on the `Future`
@@ -87,11 +72,6 @@ LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/suggest-missing-await.rs:18:18
-   |
-LL | async fn dummy() {}
-   |                  ^ checked the `Output` of this `async fn`, expected opaque type
    = note: expected opaque type `impl Future<Output = ()>`
                 found unit type `()`
 help: consider `await`ing on the `Future`
@@ -108,11 +88,6 @@ LL |     let _x = match dummy() {
 LL |         () => {}
    |         ^^ expected opaque type, found `()`
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/suggest-missing-await.rs:18:18
-   |
-LL | async fn dummy() {}
-   |                  ^ checked the `Output` of this `async fn`, expected opaque type
    = note: expected opaque type `impl Future<Output = ()>`
                 found unit type `()`
 help: consider `await`ing on the `Future`
@@ -129,11 +104,6 @@ LL |     match dummy_result() {
 LL |         Ok(_) => {}
    |         ^^^^^ expected opaque type, found `Result<_, _>`
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/suggest-missing-await.rs:57:28
-   |
-LL | async fn dummy_result() -> Result<(), ()> {
-   |                            ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type
    = note: expected opaque type `impl Future<Output = Result<(), ()>>`
                      found enum `Result<_, _>`
 help: consider `await`ing on the `Future`
@@ -150,11 +120,6 @@ LL |     match dummy_result() {
 LL |         Err(_) => {}
    |         ^^^^^^ expected opaque type, found `Result<_, _>`
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/suggest-missing-await.rs:57:28
-   |
-LL | async fn dummy_result() -> Result<(), ()> {
-   |                            ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type
    = note: expected opaque type `impl Future<Output = Result<(), ()>>`
                      found enum `Result<_, _>`
 help: consider `await`ing on the `Future`
index de9dc19af29beeb4b10fee7cfd4032fbb0cada71..586d2568c306fe4877ba9c4c517d055a5e8b52c3 100644 (file)
@@ -3,7 +3,7 @@ fn main() {
     let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
     let vr = v.iter().filter(|x| {
         *x % 2 == 0
-        //~^ ERROR cannot mod `&&{integer}` by `{integer}`
+        //~^ ERROR cannot calculate the remainder of `&&{integer}` divided by `{integer}`
     });
     println!("{:?}", vr);
 }
index 2616c560cbefb6c320808d9086976a0b65ac570e..48ee445466e35a8d37d0b78f5a9368d98100ad4b 100644 (file)
@@ -3,7 +3,7 @@ fn main() {
     let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
     let vr = v.iter().filter(|x| {
         x % 2 == 0
-        //~^ ERROR cannot mod `&&{integer}` by `{integer}`
+        //~^ ERROR cannot calculate the remainder of `&&{integer}` divided by `{integer}`
     });
     println!("{:?}", vr);
 }
index 34826d2f4bf7ab2932657a08c53a606ded25d406..2e8aeebc681d6ed1cecb10cbd7f04e18a2454971 100644 (file)
@@ -1,4 +1,4 @@
-error[E0369]: cannot mod `&&{integer}` by `{integer}`
+error[E0369]: cannot calculate the remainder of `&&{integer}` divided by `{integer}`
   --> $DIR/binary-op-on-double-ref.rs:5:11
    |
 LL |         x % 2 == 0
index 9719c3afa68c13fb5347f9b23edfd4830460a861..54c8838e48f113675dbfc6b8ef3cead310657e49 100644 (file)
@@ -11,7 +11,7 @@ fn main() {
 
     a / a; //~ ERROR cannot divide `A` by `A`
 
-    a % a; //~ ERROR cannot mod `A` by `A`
+    a % a; //~ ERROR cannot calculate the remainder of `A` divided by `A`
 
     a & a; //~ ERROR no implementation for `A & A`
 
index 6e236ca5296a17eee6b9489dbcb05e4b3a4b32b6..cca1da3b6ac49ee2a0b1316c0eb0d8a004af73de 100644 (file)
@@ -62,7 +62,7 @@ LL | struct A;
 note: the trait `Div` must be implemented
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 
-error[E0369]: cannot mod `A` by `A`
+error[E0369]: cannot calculate the remainder of `A` divided by `A`
   --> $DIR/issue-28837.rs:14:7
    |
 LL |     a % a;
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/borrowck/issue-95079-missing-move-in-nested-closure.fixed b/tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.fixed
new file mode 100644 (file)
index 0000000..1a08470
--- /dev/null
@@ -0,0 +1,26 @@
+// run-rustfix
+#![allow(dead_code, path_statements)]
+fn foo1(s: &str) -> impl Iterator<Item = String> + '_ {
+    None.into_iter()
+        .flat_map(move |()| s.chars().map(move |c| format!("{}{}", c, s)))
+        //~^ ERROR captured variable cannot escape `FnMut` closure body
+        //~| HELP consider adding 'move' keyword before the nested closure
+}
+
+fn foo2(s: &str) -> impl Sized + '_ {
+    move |()| s.chars().map(move |c| format!("{}{}", c, s))
+    //~^ ERROR lifetime may not live long enough
+    //~| HELP consider adding 'move' keyword before the nested closure
+}
+
+pub struct X;
+pub fn foo3<'a>(
+    bar: &'a X,
+) -> impl Iterator<Item = ()> + 'a {
+    Some(()).iter().flat_map(move |()| {
+        Some(()).iter().map(move |()| { bar; }) //~ ERROR captured variable cannot escape
+        //~^ HELP consider adding 'move' keyword before the nested closure
+    })
+}
+
+fn main() {}
index 95847d8d301a65249988a6bf843bdd7fd194858d..b93292e3589d371a67bad831dc716efc96ff59d0 100644 (file)
@@ -1,3 +1,5 @@
+// run-rustfix
+#![allow(dead_code, path_statements)]
 fn foo1(s: &str) -> impl Iterator<Item = String> + '_ {
     None.into_iter()
         .flat_map(move |()| s.chars().map(|c| format!("{}{}", c, s)))
@@ -11,4 +13,14 @@ fn foo2(s: &str) -> impl Sized + '_ {
     //~| HELP consider adding 'move' keyword before the nested closure
 }
 
+pub struct X;
+pub fn foo3<'a>(
+    bar: &'a X,
+) -> impl Iterator<Item = ()> + 'a {
+    Some(()).iter().flat_map(move |()| {
+        Some(()).iter().map(|()| { bar; }) //~ ERROR captured variable cannot escape
+        //~^ HELP consider adding 'move' keyword before the nested closure
+    })
+}
+
 fn main() {}
index 2eae614a2f5987504231e3960ed06c097fab10b2..776c338deacf40f4c6d2db778e8e710f44557d40 100644 (file)
@@ -1,5 +1,5 @@
 error: captured variable cannot escape `FnMut` closure body
-  --> $DIR/issue-95079-missing-move-in-nested-closure.rs:3:29
+  --> $DIR/issue-95079-missing-move-in-nested-closure.rs:5:29
    |
 LL | fn foo1(s: &str) -> impl Iterator<Item = String> + '_ {
    |         - variable defined here
@@ -7,7 +7,7 @@ LL |     None.into_iter()
 LL |         .flat_map(move |()| s.chars().map(|c| format!("{}{}", c, s)))
    |                           - -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                           | |
-   |                           | returns a reference to a captured variable which escapes the closure body
+   |                           | returns a closure that contains a reference to a captured variable, which then escapes the closure body
    |                           | variable captured here
    |                           inferred to be a `FnMut` closure
    |
@@ -19,12 +19,12 @@ LL |         .flat_map(move |()| s.chars().map(move |c| format!("{}{}", c, s)))
    |                                           ++++
 
 error: lifetime may not live long enough
-  --> $DIR/issue-95079-missing-move-in-nested-closure.rs:9:15
+  --> $DIR/issue-95079-missing-move-in-nested-closure.rs:11:15
    |
 LL |     move |()| s.chars().map(|c| format!("{}{}", c, s))
    |     --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
    |     |       |
-   |     |       return type of closure `Map<Chars<'_>, [closure@$DIR/issue-95079-missing-move-in-nested-closure.rs:9:29: 9:32]>` contains a lifetime `'2`
+   |     |       return type of closure `Map<Chars<'_>, [closure@$DIR/issue-95079-missing-move-in-nested-closure.rs:11:29: 11:32]>` contains a lifetime `'2`
    |     lifetime `'1` represents this closure's body
    |
    = note: closure implements `Fn`, so references to captured variables can't escape the closure
@@ -33,5 +33,26 @@ help: consider adding 'move' keyword before the nested closure
 LL |     move |()| s.chars().map(move |c| format!("{}{}", c, s))
    |                             ++++
 
-error: aborting due to 2 previous errors
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/issue-95079-missing-move-in-nested-closure.rs:21:9
+   |
+LL |     bar: &'a X,
+   |     --- variable defined here
+LL | ) -> impl Iterator<Item = ()> + 'a {
+LL |     Some(()).iter().flat_map(move |()| {
+   |                                      - inferred to be a `FnMut` closure
+LL |         Some(()).iter().map(|()| { bar; })
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^^
+   |         |                          |
+   |         |                          variable captured here
+   |         returns a closure that contains a reference to a captured variable, which then escapes the closure body
+   |
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
+help: consider adding 'move' keyword before the nested closure
+   |
+LL |         Some(()).iter().map(move |()| { bar; })
+   |                             ++++
+
+error: aborting due to 3 previous errors
 
index 50d9a480ad1e59060bf9b41cc8441d46f55a2f35..98f1558b7ffe18d5493f4628ac97cd3738feb44a 100644 (file)
 trait Object: Marker1 {}
 
 // A supertrait marker is illegal...
-impl !Marker1 for dyn Object + Marker2 { }   //~ ERROR E0371
+impl !Marker1 for dyn Object + Marker2 {} //~ ERROR E0371
+                                          //~^ ERROR 0321
 // ...and also a direct component.
-impl !Marker2 for dyn Object + Marker2 { }   //~ ERROR E0371
-
-// But implementing a marker if it is not present is OK.
-impl !Marker2 for dyn Object {} // OK
+impl !Marker2 for dyn Object + Marker2 {} //~ ERROR E0371
+                                          //~^ ERROR 0321
 
 // A non-principal trait-object type is orphan even in its crate.
 impl !Send for dyn Marker2 {} //~ ERROR E0117
 
-// And impl'ing a remote marker for a local trait object is forbidden
-// by one of these special orphan-like rules.
+// Implementing a marker for a local trait object is forbidden by a special
+// orphan-like rule.
+impl !Marker2 for dyn Object {} //~ ERROR E0321
 impl !Send for dyn Object {} //~ ERROR E0321
 impl !Send for dyn Object + Marker2 {} //~ ERROR E0321
 
-fn main() { }
+// Blanket impl that applies to dyn Object is equally problematic.
+auto trait Marker3 {}
+impl<T: ?Sized> !Marker3 for T {} //~ ERROR E0321
+
+auto trait Marker4 {}
+impl<T> !Marker4 for T {} // okay
+
+fn main() {}
index c364c707ff9eac202517a2a371fc43b01b498760..ea38afc40ce80bf82ad8bf5702984152899b02e5 100644 (file)
@@ -1,17 +1,41 @@
 error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
   --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1
    |
-LL | impl !Marker1 for dyn Object + Marker2 { }
+LL | impl !Marker1 for dyn Object + Marker2 {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
 
+error[E0321]: traits with a default impl, like `Marker1`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
+  --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1
+   |
+LL | impl !Marker1 for dyn Object + Marker2 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: a trait object implements `Marker1` if and only if `Marker1` is one of the trait object's trait bounds
+
 error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
-  --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:17:1
+  --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1
    |
-LL | impl !Marker2 for dyn Object + Marker2 { }
+LL | impl !Marker2 for dyn Object + Marker2 {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
 
+error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
+  --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1
+   |
+LL | impl !Marker2 for dyn Object + Marker2 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
+
+error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + 'static)`
+  --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:26:1
+   |
+LL | impl !Marker2 for dyn Object {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
+
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
-  --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:23:1
+  --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:22:1
    |
 LL | impl !Send for dyn Marker2 {}
    | ^^^^^^^^^^^^^^^-----------
@@ -33,7 +57,15 @@ error[E0321]: cross-crate traits with a default impl, like `Send`, can only be i
 LL | impl !Send for dyn Object + Marker2 {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
 
-error: aborting due to 5 previous errors
+error[E0321]: traits with a default impl, like `Marker3`, cannot be implemented for generic type `T`
+  --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:32:1
+   |
+LL | impl<T: ?Sized> !Marker3 for T {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: a trait object implements `Marker3` if and only if `Marker3` is one of the trait object's trait bounds
+
+error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0117, E0321, E0371.
 For more information about an error, try `rustc --explain E0117`.
index faac6d983f31e7e8783678c3ac2c7246ea9fe539..db2e2b4509a2af6f5c85d77d5722d8cae7355792 100644 (file)
 trait Object: Marker1 {}
 
 // A supertrait marker is illegal...
-impl Marker1 for dyn Object + Marker2 { }   //~ ERROR E0371
+impl Marker1 for dyn Object + Marker2 {} //~ ERROR E0371
+                                         //~^ ERROR E0321
 // ...and also a direct component.
-impl Marker2 for dyn Object + Marker2 { }   //~ ERROR E0371
-
-// But implementing a marker if it is not present is OK.
-impl Marker2 for dyn Object {} // OK
+impl Marker2 for dyn Object + Marker2 {} //~ ERROR E0371
+                                         //~^ ERROR E0321
 
 // A non-principal trait-object type is orphan even in its crate.
 unsafe impl Send for dyn Marker2 {} //~ ERROR E0117
 
-// And impl'ing a remote marker for a local trait object is forbidden
-// by one of these special orphan-like rules.
+// Implementing a marker for a local trait object is forbidden by a special
+// orphan-like rule.
+impl Marker2 for dyn Object {} //~ ERROR E0321
 unsafe impl Send for dyn Object {} //~ ERROR E0321
 unsafe impl Send for dyn Object + Marker2 {} //~ ERROR E0321
 
-fn main() { }
+// Blanket impl that applies to dyn Object is equally problematic.
+auto trait Marker3 {}
+impl<T: ?Sized> Marker3 for T {} //~ ERROR E0321
+
+auto trait Marker4 {}
+impl<T> Marker4 for T {} // okay
+
+fn main() {}
index b80429794f92cb2b76eddef9a4657600934ad36c..2a8713bc327942496550e57aa390781c10a741c2 100644 (file)
@@ -1,17 +1,41 @@
 error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
   --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1
    |
-LL | impl Marker1 for dyn Object + Marker2 { }
+LL | impl Marker1 for dyn Object + Marker2 {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
 
+error[E0321]: traits with a default impl, like `Marker1`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
+  --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1
+   |
+LL | impl Marker1 for dyn Object + Marker2 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: a trait object implements `Marker1` if and only if `Marker1` is one of the trait object's trait bounds
+
 error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
-  --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:17:1
+  --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:18:1
    |
-LL | impl Marker2 for dyn Object + Marker2 { }
+LL | impl Marker2 for dyn Object + Marker2 {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
 
+error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
+  --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:18:1
+   |
+LL | impl Marker2 for dyn Object + Marker2 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
+
+error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + 'static)`
+  --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:26:1
+   |
+LL | impl Marker2 for dyn Object {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
+
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
-  --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:23:1
+  --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:22:1
    |
 LL | unsafe impl Send for dyn Marker2 {}
    | ^^^^^^^^^^^^^^^^^^^^^-----------
@@ -33,7 +57,15 @@ error[E0321]: cross-crate traits with a default impl, like `Send`, can only be i
 LL | unsafe impl Send for dyn Object + Marker2 {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
 
-error: aborting due to 5 previous errors
+error[E0321]: traits with a default impl, like `Marker3`, cannot be implemented for generic type `T`
+  --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:32:1
+   |
+LL | impl<T: ?Sized> Marker3 for T {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: a trait object implements `Marker3` if and only if `Marker3` is one of the trait object's trait bounds
+
+error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0117, E0321, E0371.
 For more information about an error, try `rustc --explain E0117`.
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 8f8a8cee3a0ccfbed0c1d5b6e54ee94f29f0df00..81f28c1755deb452976804391ac6d6b5f9ce0d0b 100644 (file)
@@ -1,8 +1,7 @@
 // compile-flags: -Ztreat-err-as-bug=1
 // failure-status: 101
 // rustc-env:RUST_BACKTRACE=1
-// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
-// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "\nerror: .*unexpectedly panicked.*\n\n" -> ""
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
index b97975c4cd9e54b119b7165d38df8697949f9972..01fb8153cf3846c9be84c82096379456d5c275fc 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const-eval-query-stack.rs:17:16
+  --> $DIR/const-eval-query-stack.rs:16:16
    |
 LL | const X: i32 = 1 / 0;
    |                ^^^^^ attempt to divide `1_i32` by zero
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
 
index b4874cef134f77df98fd94427bf3a878021c54bf..5bca83e87f878b2ed1eac5c0bf1773a6bb18e429 100644 (file)
@@ -98,7 +98,7 @@ impl ::core::marker::Copy for Point { }
 impl ::core::fmt::Debug for Point {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         ::core::fmt::Formatter::debug_struct_field2_finish(f, "Point", "x",
-            &&self.x, "y", &&self.y)
+            &self.x, "y", &&self.y)
     }
 }
 #[automatically_derived]
@@ -183,7 +183,7 @@ impl ::core::marker::Copy for PackedPoint { }
 impl ::core::fmt::Debug for PackedPoint {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         ::core::fmt::Formatter::debug_struct_field2_finish(f, "PackedPoint",
-            "x", &&{ self.x }, "y", &&{ self.y })
+            "x", &{ self.x }, "y", &&{ self.y })
     }
 }
 #[automatically_derived]
@@ -209,7 +209,7 @@ impl ::core::marker::StructuralPartialEq for PackedPoint { }
 impl ::core::cmp::PartialEq for PackedPoint {
     #[inline]
     fn eq(&self, other: &PackedPoint) -> bool {
-        { self.x } == { other.x } && { self.y } == { other.y }
+        ({ self.x }) == ({ other.x }) && ({ self.y }) == ({ other.y })
     }
 }
 #[automatically_derived]
@@ -277,8 +277,8 @@ impl ::core::fmt::Debug for Big {
         let names: &'static _ =
             &["b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8"];
         let values: &[&dyn ::core::fmt::Debug] =
-            &[&&self.b1, &&self.b2, &&self.b3, &&self.b4, &&self.b5,
-                        &&self.b6, &&self.b7, &&self.b8];
+            &[&self.b1, &self.b2, &self.b3, &self.b4, &self.b5, &self.b6,
+                        &self.b7, &&self.b8];
         ::core::fmt::Formatter::debug_struct_fields_finish(f, "Big", names,
             values)
     }
@@ -565,7 +565,7 @@ impl<T: ::core::fmt::Debug + Trait, U: ::core::fmt::Debug> ::core::fmt::Debug
     for Generic<T, U> where T::A: ::core::fmt::Debug {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         ::core::fmt::Formatter::debug_struct_field3_finish(f, "Generic", "t",
-            &&self.t, "ta", &&self.ta, "u", &&self.u)
+            &self.t, "ta", &self.ta, "u", &&self.u)
     }
 }
 #[automatically_derived]
@@ -682,7 +682,7 @@ impl<T: ::core::fmt::Debug + ::core::marker::Copy + Trait,
     {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         ::core::fmt::Formatter::debug_tuple_field3_finish(f, "PackedGeneric",
-            &&{ self.0 }, &&{ self.1 }, &&{ self.2 })
+            &{ self.0 }, &{ self.1 }, &&{ self.2 })
     }
 }
 #[automatically_derived]
@@ -718,8 +718,8 @@ impl<T: ::core::cmp::PartialEq + ::core::marker::Copy + Trait,
     ::core::marker::Copy {
     #[inline]
     fn eq(&self, other: &PackedGeneric<T, U>) -> bool {
-        { self.0 } == { other.0 } && { self.1 } == { other.1 } &&
-            { self.2 } == { other.2 }
+        ({ self.0 }) == ({ other.0 }) && ({ self.1 }) == ({ other.1 }) &&
+            ({ self.2 }) == ({ other.2 })
     }
 }
 #[automatically_derived]
@@ -1084,7 +1084,7 @@ impl ::core::fmt::Debug for Mixed {
                     &__self_0),
             Mixed::S { d1: __self_0, d2: __self_1 } =>
                 ::core::fmt::Formatter::debug_struct_field2_finish(f, "S",
-                    "d1", &__self_0, "d2", &__self_1),
+                    "d1", __self_0, "d2", &__self_1),
         }
     }
 }
index bfe1ed32859b928fb4886a9f05a17bfc8332cdb4..589b2c3784926dc5a35ef647a26f02be58708b96 100644 (file)
@@ -2,7 +2,12 @@ error: expected field pattern, found `...`
   --> $DIR/issue-46718-struct-pattern-dotdotdot.rs:11:55
    |
 LL |             PersonalityInventory { expressivity: exp, ... } => exp
-   |                                                       ^^^ help: to omit remaining fields, use one fewer `.`: `..`
+   |                                                       ^^^
+   |
+help: to omit remaining fields, use `..`
+   |
+LL |             PersonalityInventory { expressivity: exp, .. } => exp
+   |                                                       ~~
 
 error: aborting due to previous error
 
index 62e28efab5820f73b90931e1041d45264a839d0a..0365d87a6f82aae88f3b23ce85dd8f398d69b2a1 100644 (file)
@@ -7,13 +7,13 @@ LL | #![feature(dyn_star)]
    = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0277]: `AlignedUsize` needs to be a pointer-sized type
+error[E0277]: `AlignedUsize` needs to have the same alignment and size as a pointer
   --> $DIR/align.rs:15:13
    |
 LL |     let x = AlignedUsize(12) as dyn* Debug;
-   |             ^^^^^^^^^^^^^^^^ `AlignedUsize` needs to be a pointer-sized type
+   |             ^^^^^^^^^^^^^^^^ `AlignedUsize` needs to be a pointer-like type
    |
-   = help: the trait `PointerSized` is not implemented for `AlignedUsize`
+   = help: the trait `PointerLike` is not implemented for `AlignedUsize`
 
 error: aborting due to previous error; 1 warning emitted
 
index fb41a05a0660ba19e45dc5f652b43fdf0f856111..6679997a9402917a5e269ce9ff576be23a481f07 100644 (file)
@@ -13,5 +13,5 @@
 
 fn main() {
     let x = AlignedUsize(12) as dyn* Debug;
-    //[over_aligned]~^ ERROR `AlignedUsize` needs to be a pointer-sized type
+    //[over_aligned]~^ ERROR `AlignedUsize` needs to have the same alignment and size as a pointer
 }
index e19e36cc7d7b5a7ed70400259361b3d009e3f5a8..85749aa7b00e2a886db52603620c04cdd4e05662 100644 (file)
@@ -9,7 +9,7 @@ fn dyn_debug(_: (dyn* Debug + '_)) {
 
 fn polymorphic<T: Debug + ?Sized>(t: &T) {
     dyn_debug(t);
-    //~^ ERROR `&T` needs to be a pointer-sized type
+    //~^ ERROR `&T` needs to have the same alignment and size as a pointer
 }
 
 fn main() {}
index 53ccbe43dcc9eea389cb3712f2e88028d378a8b6..350630f794138d31a4c28ffe45ed5c0bb0e29fb4 100644 (file)
@@ -1,14 +1,14 @@
-error[E0277]: `&T` needs to be a pointer-sized type
+error[E0277]: `&T` needs to have the same alignment and size as a pointer
   --> $DIR/check-size-at-cast-polymorphic-bad.rs:11:15
    |
 LL |     dyn_debug(t);
-   |               ^ `&T` needs to be a pointer-sized type
+   |               ^ `&T` needs to be a pointer-like type
    |
-   = help: the trait `PointerSized` is not implemented for `&T`
+   = help: the trait `PointerLike` is not implemented for `&T`
 help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
-LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerSized {
-   |                                          ++++++++++++++++++++++
+LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
+   |                                          +++++++++++++++++++++
 
 error: aborting due to previous error
 
index 1f22f798361541600bc877d8ee90fe2fe0565d2c..17bc4f303bffabd1ad541756d76b45e791fa61c4 100644 (file)
@@ -5,6 +5,6 @@
 
 fn main() {
     let i = [1, 2, 3, 4] as dyn* Debug;
-    //~^ ERROR `[i32; 4]` needs to be a pointer-sized type
+    //~^ ERROR `[i32; 4]` needs to have the same alignment and size as a pointer
     dbg!(i);
 }
index af2a1ccf71c6d6e7851c389a030aa4a0d43e2c0f..19700b40644006df9e1b388ade33cc10dad87b38 100644 (file)
@@ -1,10 +1,10 @@
-error[E0277]: `[i32; 4]` needs to be a pointer-sized type
+error[E0277]: `[i32; 4]` needs to have the same alignment and size as a pointer
   --> $DIR/check-size-at-cast.rs:7:13
    |
 LL |     let i = [1, 2, 3, 4] as dyn* Debug;
-   |             ^^^^^^^^^^^^ `[i32; 4]` needs to be a pointer-sized type
+   |             ^^^^^^^^^^^^ `[i32; 4]` needs to be a pointer-like type
    |
-   = help: the trait `PointerSized` is not implemented for `[i32; 4]`
+   = help: the trait `PointerLike` is not implemented for `[i32; 4]`
 
 error: aborting due to previous error
 
index 74ccd6a1889cd22c7028bb3f260b0f3c412f1bfd..e60144fea74c348aa3a425f99581d59b3f4f5bfd 100644 (file)
@@ -7,13 +7,13 @@ LL | #![feature(dyn_star, trait_upcasting)]
    = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0277]: `dyn* Foo` needs to be a pointer-sized type
+error[E0277]: `dyn* Foo` needs to have the same alignment and size as a pointer
   --> $DIR/upcast.rs:30:23
    |
 LL |     let w: dyn* Bar = w;
-   |                       ^ `dyn* Foo` needs to be a pointer-sized type
+   |                       ^ `dyn* Foo` needs to be a pointer-like type
    |
-   = help: the trait `PointerSized` is not implemented for `dyn* Foo`
+   = help: the trait `PointerLike` is not implemented for `dyn* Foo`
 
 error: aborting due to previous error; 1 warning emitted
 
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 7aeb5a49a1b58a5be8ff5f799e5d5c4b8fb1c5f1..aa20a4d4c653a871d276fdf45ed00f7fae764ccf 100644 (file)
@@ -3,3 +3,13 @@
 
 #[ffi_const] //~ ERROR `#[ffi_const]` may only be used on foreign functions
 pub fn foo() {}
+
+#[ffi_const] //~ ERROR `#[ffi_const]` may only be used on foreign functions
+macro_rules! bar {
+    () => ()
+}
+
+extern "C" {
+    #[ffi_const] //~ ERROR `#[ffi_const]` may only be used on foreign functions
+    static INT: i32;
+}
index bc3c12eaf981b96f663a1d2b662f7d69b2e2139d..394b98f89712a6f7380d1921e24132a89f4b0b52 100644 (file)
@@ -4,6 +4,18 @@ error[E0756]: `#[ffi_const]` may only be used on foreign functions
 LL | #[ffi_const]
    | ^^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0756]: `#[ffi_const]` may only be used on foreign functions
+  --> $DIR/ffi_const.rs:7:1
+   |
+LL | #[ffi_const]
+   | ^^^^^^^^^^^^
+
+error[E0756]: `#[ffi_const]` may only be used on foreign functions
+  --> $DIR/ffi_const.rs:13:5
+   |
+LL |     #[ffi_const]
+   |     ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0756`.
index c37d34c8784bbf373cb003d1529c9175a15e3385..6d2f3a614ec97154f344223a35be02d6c8ed216e 100644 (file)
@@ -3,3 +3,13 @@
 
 #[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on foreign functions
 pub fn foo() {}
+
+#[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on foreign functions
+macro_rules! bar {
+    () => ()
+}
+
+extern "C" {
+    #[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on foreign functions
+    static INT: i32;
+}
index bc911c85ddb296c13fb209fa85ae107113f9bac8..8b61a4b609fc08e9e1f1dffbbf9e0be36615147d 100644 (file)
@@ -4,6 +4,18 @@ error[E0755]: `#[ffi_pure]` may only be used on foreign functions
 LL | #[ffi_pure]
    | ^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0755]: `#[ffi_pure]` may only be used on foreign functions
+  --> $DIR/ffi_pure.rs:7:1
+   |
+LL | #[ffi_pure]
+   | ^^^^^^^^^^^
+
+error[E0755]: `#[ffi_pure]` may only be used on foreign functions
+  --> $DIR/ffi_pure.rs:13:5
+   |
+LL |     #[ffi_pure]
+   |     ^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0755`.
index 845e18df11b54f8975fef122b0a17ceceea2d6ac..8195d0e48636927b6a7410c18637a451c516773b 100644 (file)
@@ -3,3 +3,13 @@
 
 #[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions
 pub fn foo() {}
+
+#[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions
+macro_rules! bar {
+    () => ()
+}
+
+extern "C" {
+    #[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions
+    static INT: i32;
+}
index 2b7f5694f02069b12a51cf0ecdf512ef5ee13a6a..0abe7613f1493a0ce7521c374577b92509ea80f9 100644 (file)
@@ -4,6 +4,18 @@ error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions
 LL | #[ffi_returns_twice]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions
+  --> $DIR/ffi_returns_twice.rs:7:1
+   |
+LL | #[ffi_returns_twice]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions
+  --> $DIR/ffi_returns_twice.rs:13:5
+   |
+LL |     #[ffi_returns_twice]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0724`.
diff --git a/tests/ui/fmt/format-string-wrong-order.rs b/tests/ui/fmt/format-string-wrong-order.rs
new file mode 100644 (file)
index 0000000..0bad540
--- /dev/null
@@ -0,0 +1,15 @@
+fn main() {
+    let bar = 3;
+    format!("{?:}", bar);
+    //~^ ERROR invalid format string: expected format parameter to occur after `:`
+    format!("{?:bar}");
+    //~^ ERROR invalid format string: expected format parameter to occur after `:`
+    format!("{?:?}", bar);
+    //~^ ERROR invalid format string: expected format parameter to occur after `:`
+    format!("{??}", bar);
+    //~^ ERROR invalid format string: expected `'}'`, found `'?'`
+    format!("{?;bar}");
+    //~^ ERROR invalid format string: expected `'}'`, found `'?'`
+    format!("{?:#?}", bar);
+    //~^ ERROR invalid format string: expected format parameter to occur after `:`
+}
diff --git a/tests/ui/fmt/format-string-wrong-order.stderr b/tests/ui/fmt/format-string-wrong-order.stderr
new file mode 100644 (file)
index 0000000..461af35
--- /dev/null
@@ -0,0 +1,54 @@
+error: invalid format string: expected format parameter to occur after `:`
+  --> $DIR/format-string-wrong-order.rs:3:15
+   |
+LL |     format!("{?:}", bar);
+   |               ^ expected `?` to occur after `:` in format string
+   |
+   = note: `?` comes after `:`, try `:?` instead
+
+error: invalid format string: expected format parameter to occur after `:`
+  --> $DIR/format-string-wrong-order.rs:5:15
+   |
+LL |     format!("{?:bar}");
+   |               ^ expected `?` to occur after `:` in format string
+   |
+   = note: `?` comes after `:`, try `bar:?` instead
+
+error: invalid format string: expected format parameter to occur after `:`
+  --> $DIR/format-string-wrong-order.rs:7:15
+   |
+LL |     format!("{?:?}", bar);
+   |               ^ expected `?` to occur after `:` in format string
+   |
+   = note: `?` comes after `:`, try `:?` instead
+
+error: invalid format string: expected `'}'`, found `'?'`
+  --> $DIR/format-string-wrong-order.rs:9:15
+   |
+LL |     format!("{??}", bar);
+   |              -^ expected `}` in format string
+   |              |
+   |              because of this opening brace
+   |
+   = note: if you intended to print `{`, you can escape it using `{{`
+
+error: invalid format string: expected `'}'`, found `'?'`
+  --> $DIR/format-string-wrong-order.rs:11:15
+   |
+LL |     format!("{?;bar}");
+   |              -^ expected `}` in format string
+   |              |
+   |              because of this opening brace
+   |
+   = note: if you intended to print `{`, you can escape it using `{{`
+
+error: invalid format string: expected format parameter to occur after `:`
+  --> $DIR/format-string-wrong-order.rs:13:15
+   |
+LL |     format!("{?:#?}", bar);
+   |               ^ expected `?` to occur after `:` in format string
+   |
+   = note: `?` comes after `:`, try `:?` instead
+
+error: aborting due to 6 previous errors
+
index bb741c0ef93fa8bf0d523f610c767200256fdece..5a18983a3fa709b892d0efa52feae2183d90a4aa 100644 (file)
@@ -3,7 +3,7 @@
 // known-bug: #106191
 // unset-rustc-env:RUST_BACKTRACE
 // had to be reverted
-// error-pattern:internal compiler error
+// error-pattern:unexpectedly panicked
 // failure-status:101
 // dont-check-compiler-stderr
 
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 7ba2b6d857cd0207ae19ee3eee3806ba65ad7f34..30173b1b4be031eb2642eab7234bb7b65e439548 100644 (file)
@@ -2,7 +2,8 @@ fn main() {
     let x = 42;
     match x {
         0..=73 => {},
-        74..=> {},   //~ ERROR unexpected `=>` after open range
-                     //~^ ERROR expected one of `=>`, `if`, or `|`, found `>`
+        74..=> {},
+        //~^ ERROR unexpected `>` after inclusive range
+        //~| NOTE this is parsed as an inclusive range `..=`
     }
 }
index 9ba6d15113cd648775785808181b66bb0782d73c..cb7f998df7a5b1471191ee7c46381b2662caf061 100644 (file)
@@ -1,19 +1,15 @@
-error: unexpected `=>` after open range
-  --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:11
+error: unexpected `>` after inclusive range
+  --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:14
    |
 LL |         74..=> {},
-   |           ^^^
+   |           ---^
+   |           |
+   |           this is parsed as an inclusive range `..=`
    |
 help: add a space between the pattern and `=>`
    |
 LL |         74.. => {},
    |             +
 
-error: expected one of `=>`, `if`, or `|`, found `>`
-  --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:14
-   |
-LL |         74..=> {},
-   |              ^ expected one of `=>`, `if`, or `|`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
index feedfc40aaf4944a747f2add2a0d05a6f78a1a24..fd0358421ebf9599c9e6a13c685f1e77d4e36a7e 100644 (file)
@@ -39,7 +39,7 @@ note: ...which requires type-checking `cycle1`...
    |
 LL |     send(cycle2().clone());
    |     ^^^^
-   = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`...
+   = note: ...which requires evaluating trait selection obligation `cycle2::{opaque#0}: core::marker::Send`...
 note: ...which requires computing type of `cycle2::{opaque#0}`...
   --> $DIR/auto-trait-leak.rs:19:16
    |
@@ -80,7 +80,7 @@ note: ...which requires type-checking `cycle2`...
    |
 LL |     send(cycle1().clone());
    |     ^^^^
-   = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`...
+   = note: ...which requires evaluating trait selection obligation `cycle1::{opaque#0}: core::marker::Send`...
    = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in top-level module
   --> $DIR/auto-trait-leak.rs:1:1
index 4dfd772222e5de25f627958cea5d245549adff35..3ec62020e6c89c41077a681f599a9856cc2cb05a 100644 (file)
@@ -24,16 +24,6 @@ LL |     async fn owo(_: u8) {}
    |                     expected `()`, found `u8`
    |                     help: change the parameter type to match the trait: `()`
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/method-signature-matches.rs:20:25
-   |
-LL |     async fn owo(_: u8) {}
-   |                         ^ checked the `Output` of this `async fn`, expected opaque type
-note: while checking the return type of the `async fn`
-  --> $DIR/method-signature-matches.rs:20:25
-   |
-LL |     async fn owo(_: u8) {}
-   |                         ^ checked the `Output` of this `async fn`, found opaque type
 note: type in trait
   --> $DIR/method-signature-matches.rs:16:21
    |
index 6cf0c33ad919015f3852f0b4c0856f9cccc60ea3..8ff08968008bb31839eb5c65444e1044377671a3 100644 (file)
@@ -6,11 +6,6 @@ LL |     convert_result(foo())
    |     |
    |     arguments to this function are incorrect
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/issue-102605.rs:3:19
-   |
-LL | async fn foo() -> Result<(), String> {
-   |                   ^^^^^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected enum `Result<(), _>`
            found opaque type `impl Future<Output = Result<(), String>>`
 note: function defined here
index 3b4e130fdebde3e88c8da6f700867fb30abe5e94..a4b7fc1f5bc75e6e62e932461e6e3c32c0c3a1dd 100644 (file)
@@ -4,11 +4,6 @@ error[E0308]: mismatched types
 LL |     t.and_then(|t| -> _ { bar(t) });
    |                           ^^^^^^ expected `Result<_, Error>`, found opaque type
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/issue-99914.rs:13:23
-   |
-LL | async fn bar(t: Okay) {}
-   |                       ^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected enum `Result<_, Error>`
            found opaque type `impl Future<Output = ()>`
 help: try wrapping the expression in `Ok`
index 6c4aa35679d5bc9f57abb1df07a1ace6a64f70d7..f3a773837785e3a98f80e9fcc421b06006b29cb4 100644 (file)
@@ -9,9 +9,7 @@ LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResu
 
 stack backtrace:
 
-error: internal compiler error: unexpected panic
-
-
+error: the compiler unexpectedly panicked. this is a bug.
 
 
 
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/lang-items/lang-item-missing-generator.rs b/tests/ui/lang-items/lang-item-missing-generator.rs
deleted file mode 100644 (file)
index 9b9aff3..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// error-pattern: requires `generator` lang_item
-#![feature(no_core, lang_items, unboxed_closures, tuple_trait)]
-#![no_core]
-
-#[lang = "sized"] pub trait Sized { }
-
-#[lang = "tuple_trait"] pub trait Tuple { }
-
-#[lang = "fn_once"]
-#[rustc_paren_sugar]
-pub trait FnOnce<Args: Tuple> {
-    type Output;
-
-    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
-}
-
-pub fn abc() -> impl FnOnce(f32) {
-    |_| {}
-}
-
-fn main() {}
diff --git a/tests/ui/lang-items/lang-item-missing-generator.stderr b/tests/ui/lang-items/lang-item-missing-generator.stderr
deleted file mode 100644 (file)
index a24fdb5..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0635]: unknown feature `tuple_trait`
-  --> $DIR/lang-item-missing-generator.rs:2:51
-   |
-LL | #![feature(no_core, lang_items, unboxed_closures, tuple_trait)]
-   |                                                   ^^^^^^^^^^^
-
-error: requires `generator` lang_item
-  --> $DIR/lang-item-missing-generator.rs:17:17
-   |
-LL | pub fn abc() -> impl FnOnce(f32) {
-   |                 ^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0635`.
index 7398f01643f6eb9f35957c0fb07c9968ac0f54af..a3a514fb830958beb540e7452e46f0733f02c019 100644 (file)
@@ -1,4 +1,4 @@
-error: internal compiler error: unexpected panic
+error: the compiler unexpectedly panicked. this is a bug.
 
 query stack during panic:
 #0 [layout_of] computing layout of `Foo`
index 5474a67aac45a6128940aaaa61d401600ab40705..57e5259173078f1fd0da4bda7ed24dd388945b28 100644 (file)
@@ -10,10 +10,10 @@ help: add a block here
 LL |     if let Some(y) = x else {
    |                       ^
 help: remove the `if` if you meant to write a `let...else` statement
-  --> $DIR/accidental-if.rs:3:5
    |
-LL |     if let Some(y) = x else {
-   |     ^^
+LL -     if let Some(y) = x else {
+LL +     let Some(y) = x else {
+   |
 
 error: aborting due to previous error
 
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/lint/unused/issue-96606.rs b/tests/ui/lint/unused/issue-96606.rs
new file mode 100644 (file)
index 0000000..4e7c290
--- /dev/null
@@ -0,0 +1,8 @@
+#[deny(unused)]
+fn main() {
+    let arr = [0; 10];
+    let _ = arr[(0)]; //~ ERROR unnecessary parentheses around index expression
+    let _ = arr[{0}]; //~ ERROR unnecessary braces around index expression
+    let _ = arr[1 + (0)];
+    let _ = arr[{ let x = 0; x }];
+}
diff --git a/tests/ui/lint/unused/issue-96606.stderr b/tests/ui/lint/unused/issue-96606.stderr
new file mode 100644 (file)
index 0000000..e362771
--- /dev/null
@@ -0,0 +1,33 @@
+error: unnecessary parentheses around index expression
+  --> $DIR/issue-96606.rs:4:17
+   |
+LL |     let _ = arr[(0)];
+   |                 ^ ^
+   |
+note: the lint level is defined here
+  --> $DIR/issue-96606.rs:1:8
+   |
+LL | #[deny(unused)]
+   |        ^^^^^^
+   = note: `#[deny(unused_parens)]` implied by `#[deny(unused)]`
+help: remove these parentheses
+   |
+LL -     let _ = arr[(0)];
+LL +     let _ = arr[0];
+   |
+
+error: unnecessary braces around index expression
+  --> $DIR/issue-96606.rs:5:17
+   |
+LL |     let _ = arr[{0}];
+   |                 ^ ^
+   |
+   = note: `#[deny(unused_braces)]` implied by `#[deny(unused)]`
+help: remove these braces
+   |
+LL -     let _ = arr[{0}];
+LL +     let _ = arr[0];
+   |
+
+error: aborting due to 2 previous errors
+
index 5cd217df6fc2ff91c814e5c6abb980571141b802..fdc2a7666d69b0a6ccbaad809fd933bf45124919 100644 (file)
@@ -626,7 +626,7 @@ impl<T> const Trait for T {}
         stringify_item!(
             impl ~const Struct {}
         ),
-        "impl Struct {}", // FIXME
+        "impl ~const Struct {}",
     );
 
     // ItemKind::MacCall
@@ -838,7 +838,7 @@ fn test_ty() {
     assert_eq!(stringify_ty!(dyn Send + 'a), "dyn Send + 'a");
     assert_eq!(stringify_ty!(dyn 'a + Send), "dyn 'a + Send");
     assert_eq!(stringify_ty!(dyn ?Sized), "dyn ?Sized");
-    assert_eq!(stringify_ty!(dyn ~const Clone), "dyn Clone"); // FIXME
+    assert_eq!(stringify_ty!(dyn ~const Clone), "dyn ~const Clone");
     assert_eq!(stringify_ty!(dyn for<'a> Send), "dyn for<'a> Send");
 
     // TyKind::ImplTrait
@@ -846,7 +846,7 @@ fn test_ty() {
     assert_eq!(stringify_ty!(impl Send + 'a), "impl Send + 'a");
     assert_eq!(stringify_ty!(impl 'a + Send), "impl 'a + Send");
     assert_eq!(stringify_ty!(impl ?Sized), "impl ?Sized");
-    assert_eq!(stringify_ty!(impl ~const Clone), "impl Clone"); // FIXME
+    assert_eq!(stringify_ty!(impl ~const Clone), "impl ~const Clone");
     assert_eq!(stringify_ty!(impl for<'a> Send), "impl for<'a> Send");
 
     // TyKind::Paren
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) {}
+}
index a0025d7e221ae1f35b764f596f68b6449976be92..7bf08bee9222465b3d01f963615c1fc7da3ba0aa 100644 (file)
@@ -4,9 +4,7 @@ LL | fn main() { missing_ident; }
 
 stack backtrace:
 
-error: internal compiler error: unexpected panic
-
-
+error: the compiler unexpectedly panicked. this is a bug.
 
 
 
diff --git a/tests/ui/parser/anon-enums-are-ambiguous.rs b/tests/ui/parser/anon-enums-are-ambiguous.rs
new file mode 100644 (file)
index 0000000..b0173cf
--- /dev/null
@@ -0,0 +1,26 @@
+// check-pass
+
+macro_rules! test_expr {
+    ($expr:expr) => {};
+}
+
+macro_rules! test_ty {
+    ($a:ty | $b:ty) => {};
+}
+
+fn main() {
+    test_expr!(a as fn() -> B | C);
+    // Do not break the `|` operator.
+
+    test_expr!(|_: fn() -> B| C | D);
+    // Do not break `-> Ret` in closure args.
+
+    test_ty!(A | B);
+    // We can't support anon enums in arbitrary positions.
+
+    test_ty!(fn() -> A | B);
+    // Don't break fn ptrs.
+
+    test_ty!(impl Fn() -> A | B);
+    // Don't break parenthesized generics.
+}
diff --git a/tests/ui/parser/anon-enums.rs b/tests/ui/parser/anon-enums.rs
deleted file mode 100644 (file)
index 56b8a3d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-fn foo(x: bool | i32) -> i32 | f64 {
-//~^ ERROR anonymous enums are not supported
-//~| ERROR anonymous enums are not supported
-    match x {
-        x: i32 => x, //~ ERROR expected
-        true => 42.,
-        false => 0.333,
-    }
-}
-
-fn main() {
-    match foo(true) {
-        42: i32 => (), //~ ERROR expected
-        _: f64 => (), //~ ERROR expected
-        x: i32 => (), //~ ERROR expected
-    }
-}
diff --git a/tests/ui/parser/anon-enums.stderr b/tests/ui/parser/anon-enums.stderr
deleted file mode 100644 (file)
index 8415822..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-error: anonymous enums are not supported
-  --> $DIR/anon-enums.rs:1:16
-   |
-LL | fn foo(x: bool | i32) -> i32 | f64 {
-   |           ---- ^ ---
-   |
-   = help: create a named `enum` and use it here instead:
-           enum Name {
-               Variant1(bool),
-               Variant2(i32),
-           }
-
-error: anonymous enums are not supported
-  --> $DIR/anon-enums.rs:1:30
-   |
-LL | fn foo(x: bool | i32) -> i32 | f64 {
-   |                          --- ^ ---
-   |
-   = help: create a named `enum` and use it here instead:
-           enum Name {
-               Variant1(i32),
-               Variant2(f64),
-           }
-
-error: expected one of `@` or `|`, found `:`
-  --> $DIR/anon-enums.rs:5:10
-   |
-LL |         x: i32 => x,
-   |          ^ --- specifying the type of a pattern isn't supported
-   |          |
-   |          expected one of `@` or `|`
-   |
-help: maybe write a path separator here
-   |
-LL |         x::i32 => x,
-   |          ~~
-
-error: expected one of `...`, `..=`, `..`, or `|`, found `:`
-  --> $DIR/anon-enums.rs:13:11
-   |
-LL |         42: i32 => (),
-   |           ^ --- specifying the type of a pattern isn't supported
-   |           |
-   |           expected one of `...`, `..=`, `..`, or `|`
-
-error: expected `|`, found `:`
-  --> $DIR/anon-enums.rs:14:10
-   |
-LL |         _: f64 => (),
-   |          ^ --- specifying the type of a pattern isn't supported
-   |          |
-   |          expected `|`
-
-error: expected one of `@` or `|`, found `:`
-  --> $DIR/anon-enums.rs:15:10
-   |
-LL |         x: i32 => (),
-   |          ^ --- specifying the type of a pattern isn't supported
-   |          |
-   |          expected one of `@` or `|`
-   |
-help: maybe write a path separator here
-   |
-LL |         x::i32 => (),
-   |          ~~
-
-error: aborting due to 6 previous errors
-
diff --git a/tests/ui/parser/fake-anon-enums-in-macros.rs b/tests/ui/parser/fake-anon-enums-in-macros.rs
deleted file mode 100644 (file)
index 38fe8de..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// build-pass
-macro_rules! check_ty {
-    ($Z:ty) => { compile_error!("triggered"); };
-    ($X:ty | $Y:ty) => { $X };
-}
-
-macro_rules! check {
-    ($Z:ty) => { compile_error!("triggered"); };
-    ($X:ty | $Y:ty) => { };
-}
-
-check! { i32 | u8 }
-
-fn foo(x: check_ty! { i32 | u8 }) -> check_ty! { i32 | u8 } {
-    x
-}
-fn main() {
-    let x: check_ty! { i32 | u8 } = 42;
-    let _: check_ty! { i32 | u8 } = foo(x);
-}
index 038fdfb2d51b2a4fd5258fe7cc7104e51c8f86f3..2d8bd19a73108e5bf704b6d1561ab0268d9100e6 100644 (file)
@@ -209,8 +209,8 @@ note: ...which requires const checking `main::ff5`...
    |
 LL |     const async unsafe extern "C" fn ff5() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
-   = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
+   = note: ...which requires computing whether `main::ff5::{opaque#0}` is freeze...
+   = note: ...which requires evaluating trait selection obligation `main::ff5::{opaque#0}: core::marker::Freeze`...
    = note: ...which again requires computing type of `main::ff5::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in top-level module
   --> $DIR/fn-header-semantic-fail.rs:5:1
@@ -245,8 +245,8 @@ note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-f
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
-   = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
+   = note: ...which requires computing whether `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}` is freeze...
+   = note: ...which requires evaluating trait selection obligation `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}: core::marker::Freeze`...
    = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in top-level module
   --> $DIR/fn-header-semantic-fail.rs:5:1
@@ -281,8 +281,8 @@ note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-f
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
-   = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
+   = note: ...which requires computing whether `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5::{opaque#0}` is freeze...
+   = note: ...which requires evaluating trait selection obligation `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5::{opaque#0}: core::marker::Freeze`...
    = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in top-level module
   --> $DIR/fn-header-semantic-fail.rs:5:1
index 6872b8bc0afec880c9f4e66f23ca63381d8fa5bf..ba8174a823b2a30991c0179edbc664a6c8f4e202 100644 (file)
@@ -32,7 +32,12 @@ error: expected field pattern, found `...`
   --> $DIR/issue-102806.rs:21:22
    |
 LL |     let V3 { z: val, ... } = v;
-   |                      ^^^ help: to omit remaining fields, use one fewer `.`: `..`
+   |                      ^^^
+   |
+help: to omit remaining fields, use `..`
+   |
+LL |     let V3 { z: val, .. } = v;
+   |                      ~~
 
 error[E0063]: missing fields `x` and `y` in initializer of `V3`
   --> $DIR/issue-102806.rs:17:13
index 80e9ac5bedf13292da7a83650e3de4311a7e4953..e0dc356d5467bb996d9c9db592bf4dc0859e411d 100644 (file)
@@ -20,7 +20,12 @@ error: expected field pattern, found `...`
   --> $DIR/issue-63135.rs:3:8
    |
 LL | fn i(n{...,f #
-   |        ^^^ help: to omit remaining fields, use one fewer `.`: `..`
+   |        ^^^
+   |
+help: to omit remaining fields, use `..`
+   |
+LL | fn i(n{..,f #
+   |        ~~
 
 error: expected `}`, found `,`
   --> $DIR/issue-63135.rs:3:11
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
diff --git a/tests/ui/parser/type-ascription-in-pattern.rs b/tests/ui/parser/type-ascription-in-pattern.rs
new file mode 100644 (file)
index 0000000..fec168a
--- /dev/null
@@ -0,0 +1,16 @@
+fn foo(x: bool) -> i32 {
+    match x {
+        x: i32 => x, //~ ERROR expected
+        //~^ ERROR mismatched types
+        true => 42.,
+        false => 0.333,
+    }
+}
+
+fn main() {
+    match foo(true) {
+        42: i32 => (), //~ ERROR expected
+        _: f64 => (), //~ ERROR expected
+        x: i32 => (), //~ ERROR expected
+    }
+}
diff --git a/tests/ui/parser/type-ascription-in-pattern.stderr b/tests/ui/parser/type-ascription-in-pattern.stderr
new file mode 100644 (file)
index 0000000..0919075
--- /dev/null
@@ -0,0 +1,54 @@
+error: expected one of `@` or `|`, found `:`
+  --> $DIR/type-ascription-in-pattern.rs:3:10
+   |
+LL |         x: i32 => x,
+   |          ^ --- specifying the type of a pattern isn't supported
+   |          |
+   |          expected one of `@` or `|`
+   |
+help: maybe write a path separator here
+   |
+LL |         x::i32 => x,
+   |          ~~
+
+error: expected one of `...`, `..=`, `..`, or `|`, found `:`
+  --> $DIR/type-ascription-in-pattern.rs:12:11
+   |
+LL |         42: i32 => (),
+   |           ^ --- specifying the type of a pattern isn't supported
+   |           |
+   |           expected one of `...`, `..=`, `..`, or `|`
+
+error: expected `|`, found `:`
+  --> $DIR/type-ascription-in-pattern.rs:13:10
+   |
+LL |         _: f64 => (),
+   |          ^ --- specifying the type of a pattern isn't supported
+   |          |
+   |          expected `|`
+
+error: expected one of `@` or `|`, found `:`
+  --> $DIR/type-ascription-in-pattern.rs:14:10
+   |
+LL |         x: i32 => (),
+   |          ^ --- specifying the type of a pattern isn't supported
+   |          |
+   |          expected one of `@` or `|`
+   |
+help: maybe write a path separator here
+   |
+LL |         x::i32 => (),
+   |          ~~
+
+error[E0308]: mismatched types
+  --> $DIR/type-ascription-in-pattern.rs:3:19
+   |
+LL | fn foo(x: bool) -> i32 {
+   |                    --- expected `i32` because of return type
+LL |     match x {
+LL |         x: i32 => x,
+   |                   ^ expected `i32`, found `bool`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 6e47bb4930dc5306e8666c1e8fb7d407706398bc..8fe936efc8983ed96b21ecdb7ef781b6227cbe39 100644 (file)
@@ -1,15 +1,15 @@
 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 `Suspend0`: 16385 bytes
-print-type-size         field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
-print-type-size         field `.arg`: 8192 bytes
-print-type-size         field `.__awaitee`: 1 bytes
 print-type-size     variant `Unresumed`: 8192 bytes
-print-type-size         field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         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 `Returned`: 8192 bytes
-print-type-size         field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Panicked`: 8192 bytes
-print-type-size         field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size type: `std::mem::ManuallyDrop<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes
 print-type-size     field `.value`: 8192 bytes
 print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes
index 28d4a6e6cff40de7cfa64a1c4cca2655ef26d27d..7c58d6ce5ffa1e79785cd7577cbe5174c8d8f082 100644 (file)
@@ -1,10 +1,10 @@
 print-type-size type: `[generator@$DIR/generator.rs:10:5: 10:14]`: 8193 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 8192 bytes
-print-type-size         field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         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         field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Panicked`: 8192 bytes
-print-type-size         field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
-print-type-size     variant `Suspend0`: 8192 bytes
-print-type-size         field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
index 7f8f4ccae7c14c6fbe752324f214fc2eced33820..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         field `.w`: 4 bytes, alignment: 4 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         field `.z`: 4 bytes, alignment: 4 bytes
-print-type-size     variant `Unresumed`: 0 bytes
+print-type-size         local `.z`: 4 bytes, alignment: 4 bytes
 print-type-size     variant `Returned`: 0 bytes
 print-type-size     variant `Panicked`: 0 bytes
index 6103acb7b6bd9ef82e9f3c7cc73f5605f434448a..020128fa214460f0d2f6f574eb422d5314c7c5d1 100644 (file)
@@ -5,6 +5,9 @@
 // ignore-wasm32
 // ignore-sgx no support for proc-macro crate type
 // build-pass
+// force-host
+// no-prefer-dynamic
+
 #![crate_type = "proc-macro"]
 
 // FIXME: This don't work when crate-type is specified by attribute
diff --git a/tests/ui/pub/pub-ident-fn-3.rs b/tests/ui/pub/pub-ident-fn-3.rs
deleted file mode 100644 (file)
index fdbea7c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// #60115
-
-mod foo {
-    pub bar();
-    //~^ ERROR missing `fn` or `struct` for function or struct definition
-}
-
-fn main() {}
diff --git a/tests/ui/pub/pub-ident-fn-3.stderr b/tests/ui/pub/pub-ident-fn-3.stderr
deleted file mode 100644 (file)
index 6d3d4e5..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: missing `fn` or `struct` for function or struct definition
-  --> $DIR/pub-ident-fn-3.rs:4:8
-   |
-LL |     pub bar();
-   |     ---^--- help: if you meant to call a macro, try: `bar!`
-
-error: aborting due to previous error
-
diff --git a/tests/ui/pub/pub-ident-fn-or-struct-2.rs b/tests/ui/pub/pub-ident-fn-or-struct-2.rs
deleted file mode 100644 (file)
index 8f67cdd..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-pub S();
-//~^ ERROR missing `fn` or `struct` for function or struct definition
-
-fn main() {}
diff --git a/tests/ui/pub/pub-ident-fn-or-struct-2.stderr b/tests/ui/pub/pub-ident-fn-or-struct-2.stderr
deleted file mode 100644 (file)
index 047e66b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: missing `fn` or `struct` for function or struct definition
-  --> $DIR/pub-ident-fn-or-struct-2.rs:1:4
-   |
-LL | pub S();
-   | ---^- help: if you meant to call a macro, try: `S!`
-
-error: aborting due to previous error
-
diff --git a/tests/ui/pub/pub-ident-struct-2.rs b/tests/ui/pub/pub-ident-struct-2.rs
new file mode 100644 (file)
index 0000000..50db403
--- /dev/null
@@ -0,0 +1,8 @@
+// #60115
+
+mod foo {
+    pub bar();
+    //~^ ERROR missing `struct` for struct definition
+}
+
+fn main() {}
diff --git a/tests/ui/pub/pub-ident-struct-2.stderr b/tests/ui/pub/pub-ident-struct-2.stderr
new file mode 100644 (file)
index 0000000..6969a37
--- /dev/null
@@ -0,0 +1,13 @@
+error: missing `struct` for struct definition
+  --> $DIR/pub-ident-struct-2.rs:4:8
+   |
+LL |     pub bar();
+   |        ^
+   |
+help: add `struct` here to parse `bar` as a public struct
+   |
+LL |     pub struct bar();
+   |         ++++++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pub/pub-ident-struct-3.rs b/tests/ui/pub/pub-ident-struct-3.rs
new file mode 100644 (file)
index 0000000..dfa6cf2
--- /dev/null
@@ -0,0 +1,4 @@
+pub S();
+//~^ ERROR missing `struct` for struct definition
+
+fn main() {}
diff --git a/tests/ui/pub/pub-ident-struct-3.stderr b/tests/ui/pub/pub-ident-struct-3.stderr
new file mode 100644 (file)
index 0000000..d94198a
--- /dev/null
@@ -0,0 +1,13 @@
+error: missing `struct` for struct definition
+  --> $DIR/pub-ident-struct-3.rs:1:4
+   |
+LL | pub S();
+   |    ^
+   |
+help: add `struct` here to parse `S` as a public struct
+   |
+LL | pub struct S();
+   |     ++++++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pub/pub-ident-struct-4.fixed b/tests/ui/pub/pub-ident-struct-4.fixed
new file mode 100644 (file)
index 0000000..b49fa67
--- /dev/null
@@ -0,0 +1,6 @@
+// run-rustfix
+
+pub struct T(String);
+//~^ ERROR missing `struct` for struct definition
+
+fn main() {}
diff --git a/tests/ui/pub/pub-ident-struct-4.rs b/tests/ui/pub/pub-ident-struct-4.rs
new file mode 100644 (file)
index 0000000..20bc94b
--- /dev/null
@@ -0,0 +1,6 @@
+// run-rustfix
+
+pub T(String);
+//~^ ERROR missing `struct` for struct definition
+
+fn main() {}
diff --git a/tests/ui/pub/pub-ident-struct-4.stderr b/tests/ui/pub/pub-ident-struct-4.stderr
new file mode 100644 (file)
index 0000000..90c7138
--- /dev/null
@@ -0,0 +1,13 @@
+error: missing `struct` for struct definition
+  --> $DIR/pub-ident-struct-4.rs:3:4
+   |
+LL | pub T(String);
+   |    ^
+   |
+help: add `struct` here to parse `T` as a public struct
+   |
+LL | pub struct T(String);
+   |     ++++++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/query-system/no-query-in-printing-during-query-descr.rs b/tests/ui/query-system/no-query-in-printing-during-query-descr.rs
new file mode 100644 (file)
index 0000000..45b7043
--- /dev/null
@@ -0,0 +1,6 @@
+fn a() -> _ {
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+    &a
+}
+
+fn main() {}
diff --git a/tests/ui/query-system/no-query-in-printing-during-query-descr.stderr b/tests/ui/query-system/no-query-in-printing-during-query-descr.stderr
new file mode 100644 (file)
index 0000000..35e608b
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/no-query-in-printing-during-query-descr.rs:1:11
+   |
+LL | fn a() -> _ {
+   |           ^ not allowed in type signatures
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
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'
 
index 802928452709d074e8f7739d5e91edd6a352a32d..9bc3e754126db7bce9708bfe7f24fcf399fd49b1 100644 (file)
@@ -38,10 +38,10 @@ help: add a block here
 LL |     if let Some(n) = opt else {
    |                         ^
 help: remove the `if` if you meant to write a `let...else` statement
-  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:24:5
    |
-LL |     if let Some(n) = opt else {
-   |     ^^
+LL -     if let Some(n) = opt else {
+LL +     let Some(n) = opt else {
+   |
 
 error: this `if` expression is missing a block after the condition
   --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:28:5
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/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs b/tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs
new file mode 100644 (file)
index 0000000..72edfbc
--- /dev/null
@@ -0,0 +1,13 @@
+// check-pass
+
+#![feature(derive_const)]
+#![feature(const_trait_impl)]
+
+#[derive_const(PartialEq)]
+pub struct Reverse<T>(T);
+
+const fn foo(a: Reverse<i32>, b: Reverse<i32>) -> bool {
+    a == b
+}
+
+fn main() {}
index 0b89d0b160b3db12e645fe0217b414c98acdb4db..9bb87026b6418b00eaf1b8d778549f5e733583eb 100644 (file)
@@ -1,7 +1,11 @@
 // check-pass
 // compile-flags: -Zhir-stats
 // only-x86_64
-// ignore-stage1  FIXME: remove after next bootstrap bump
+
+// Type layouts sometimes change. When that happens, until the next bootstrap
+// bump occurs, stage1 and stage2 will give different outputs for this test.
+// Add an `ignore-stage1` comment marker to work around that problem during
+// that time.
 
 // The aim here is to include at least one of every different type of top-level
 // AST/HIR node reported by `-Zhir-stats`.
index c30b8a1e1f1a7c3bd74f599c7f7e3feae8d87e5f..b569993c6143edeff75e58bcf35395ba12bcee61 100644 (file)
@@ -7,6 +7,5 @@ fn main() {
     let foo = Some(Foo::Other);
 
     if let Some(Foo::Bar {_}) = foo {}
-    //~^ ERROR expected identifier, found reserved identifier `_`
-    //~| ERROR pattern does not mention field `bar` [E0027]
+    //~^ ERROR expected field pattern, found `_`
 }
index 16f751444a558c6d67cd2a567e32d3747b031ddf..2f3a150e5cba92566aadd814edcbad3e2fb000a4 100644 (file)
@@ -1,24 +1,13 @@
-error: expected identifier, found reserved identifier `_`
+error: expected field pattern, found `_`
   --> $DIR/struct-enum-ignoring-field-with-underscore.rs:9:27
    |
 LL |     if let Some(Foo::Bar {_}) = foo {}
-   |                           ^ expected identifier, found reserved identifier
-
-error[E0027]: pattern does not mention field `bar`
-  --> $DIR/struct-enum-ignoring-field-with-underscore.rs:9:17
-   |
-LL |     if let Some(Foo::Bar {_}) = foo {}
-   |                 ^^^^^^^^^^^^ missing field `bar`
-   |
-help: include the missing field in the pattern
+   |                           ^
    |
-LL |     if let Some(Foo::Bar {_, bar }) = foo {}
-   |                            ~~~~~~~
-help: if you don't care about this missing field, you can explicitly ignore it
+help: to omit remaining fields, use `..`
    |
-LL |     if let Some(Foo::Bar {_, .. }) = foo {}
-   |                            ~~~~~~
+LL |     if let Some(Foo::Bar {..}) = foo {}
+   |                           ~~
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0027`.
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`.
index b487f013d27068fc61adcb703dfcaf6c9efb766d..7be4312bfbacbdcf0ff2bf01bb10af78c303eb47 100644 (file)
@@ -15,18 +15,9 @@ fn extra_semicolon() {
     };
 }
 
-async fn async_dummy() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
-//~| NOTE while checking the return type of the `async fn`
-//~| NOTE in this expansion of desugaring of `async` block or function
-//~| NOTE checked the `Output` of this `async fn`, expected opaque type
-//~| NOTE while checking the return type of the `async fn`
-//~| NOTE in this expansion of desugaring of `async` block or function
-async fn async_dummy2() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
-//~| NOTE checked the `Output` of this `async fn`, found opaque type
-//~| NOTE while checking the return type of the `async fn`
-//~| NOTE in this expansion of desugaring of `async` block or function
-//~| NOTE while checking the return type of the `async fn`
-//~| NOTE in this expansion of desugaring of `async` block or function
+async fn async_dummy() {}
+
+async fn async_dummy2() {}
 
 async fn async_extra_semicolon_same() {
     let _ = if true {
index d7c5818abbd54b76fc7465051dc6917499f59723..567deb405fccd98332c24019c511ffc642187a62 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: `if` and `else` have incompatible types
-  --> $DIR/if-then-neeing-semi.rs:37:9
+  --> $DIR/if-then-neeing-semi.rs:28:9
    |
 LL |       let _ = if true {
    |  _____________-
@@ -15,11 +15,6 @@ LL | |
 LL | |     };
    | |_____- `if` and `else` have incompatible types
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/if-then-neeing-semi.rs:18:24
-   |
-LL | async fn async_dummy() {}
-   |                        ^ checked the `Output` of this `async fn`, found opaque type
    = note: expected unit type `()`
             found opaque type `impl Future<Output = ()>`
 help: consider `await`ing on the `Future`
@@ -33,7 +28,7 @@ LL +         async_dummy()
    |
 
 error[E0308]: `if` and `else` have incompatible types
-  --> $DIR/if-then-neeing-semi.rs:50:9
+  --> $DIR/if-then-neeing-semi.rs:41:9
    |
 LL |       let _ = if true {
    |  _____________-
@@ -49,11 +44,6 @@ LL | |
 LL | |     };
    | |_____- `if` and `else` have incompatible types
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/if-then-neeing-semi.rs:24:25
-   |
-LL | async fn async_dummy2() {}
-   |                         ^ checked the `Output` of this `async fn`, found opaque type
    = note: expected unit type `()`
             found opaque type `impl Future<Output = ()>`
 help: consider `await`ing on the `Future`
@@ -69,7 +59,7 @@ LL ~         Box::new(async_dummy2())
    |
 
 error[E0308]: `if` and `else` have incompatible types
-  --> $DIR/if-then-neeing-semi.rs:63:9
+  --> $DIR/if-then-neeing-semi.rs:54:9
    |
 LL |       let _ = if true {
    |  _____________-
@@ -85,18 +75,8 @@ LL | |
 LL | |     };
    | |_____- `if` and `else` have incompatible types
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/if-then-neeing-semi.rs:18:24
-   |
-LL | async fn async_dummy() {}
-   |                        ^ checked the `Output` of this `async fn`, expected opaque type
-note: while checking the return type of the `async fn`
-  --> $DIR/if-then-neeing-semi.rs:24:25
-   |
-LL | async fn async_dummy2() {}
-   |                         ^ checked the `Output` of this `async fn`, found opaque type
    = note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/if-then-neeing-semi.rs:18:24>)
-              found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/if-then-neeing-semi.rs:24:25>)
+              found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/if-then-neeing-semi.rs:20:25>)
    = note: distinct uses of `impl Trait` result in different opaque types
 help: consider `await`ing on both `Future`s
    |
index fae474cedb886831c23d45c676942da10da6d1a2..4af7cc9f8ec800c7a2b8b6fb50648acecf633df9 100644 (file)
@@ -14,11 +14,6 @@ LL | |         _ => cx.answer_str("hi"),
 LL | |     }
    | |_____- `match` arms have incompatible types
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/auxiliary/issue-81839.rs:6:49
-   |
-LL |     pub async fn answer_str(&self, _s: &str) -> Test {
-   |                                                 ^^^^ checked the `Output` of this `async fn`, found opaque type
    = note: expected unit type `()`
             found opaque type `impl Future<Output = Test>`
 
index 8c8abe047c2abd7413844f3d940eadf9ffff06d2..3f863cb104e0bfa48d99d5c63e4e49a60fdac892 100644 (file)
@@ -13,18 +13,9 @@ fn extra_semicolon() {
     };
 }
 
-async fn async_dummy() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
-//~| NOTE while checking the return type of the `async fn`
-//~| NOTE in this expansion of desugaring of `async` block or function
-//~| NOTE checked the `Output` of this `async fn`, expected opaque type
-//~| NOTE while checking the return type of the `async fn`
-//~| NOTE in this expansion of desugaring of `async` block or function
-async fn async_dummy2() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
-//~| NOTE checked the `Output` of this `async fn`, found opaque type
-//~| NOTE while checking the return type of the `async fn`
-//~| NOTE in this expansion of desugaring of `async` block or function
-//~| NOTE while checking the return type of the `async fn`
-//~| NOTE in this expansion of desugaring of `async` block or function
+async fn async_dummy() {}
+
+async fn async_dummy2() {}
 
 async fn async_extra_semicolon_same() {
     let _ = match true { //~ NOTE `match` arms have incompatible types
index 8d735b71f827821b72db818d12fff85008c0fea3..df18c7b0b23cceade1b2e6e8d4a47aeb0ff31ac4 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:35:18
+  --> $DIR/match-prev-arm-needing-semi.rs:26:18
    |
 LL |       let _ = match true {
    |  _____________-
@@ -15,11 +15,6 @@ LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/match-prev-arm-needing-semi.rs:16:24
-   |
-LL | async fn async_dummy() {}
-   |                        ^ checked the `Output` of this `async fn`, found opaque type
    = note: expected unit type `()`
             found opaque type `impl Future<Output = ()>`
 help: consider `await`ing on the `Future`
@@ -33,7 +28,7 @@ LL +             async_dummy()
    |
 
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:48:18
+  --> $DIR/match-prev-arm-needing-semi.rs:39:18
    |
 LL |       let _ = match true {
    |  _____________-
@@ -49,11 +44,6 @@ LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/match-prev-arm-needing-semi.rs:22:25
-   |
-LL | async fn async_dummy2() {}
-   |                         ^ checked the `Output` of this `async fn`, found opaque type
    = note: expected unit type `()`
             found opaque type `impl Future<Output = ()>`
 help: consider `await`ing on the `Future`
@@ -69,7 +59,7 @@ LL ~         false => Box::new(async_dummy2()),
    |
 
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:59:18
+  --> $DIR/match-prev-arm-needing-semi.rs:50:18
    |
 LL |       let _ = match true {
    |  _____________-
@@ -83,18 +73,8 @@ LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/match-prev-arm-needing-semi.rs:16:24
-   |
-LL | async fn async_dummy() {}
-   |                        ^ checked the `Output` of this `async fn`, expected opaque type
-note: while checking the return type of the `async fn`
-  --> $DIR/match-prev-arm-needing-semi.rs:22:25
-   |
-LL | async fn async_dummy2() {}
-   |                         ^ checked the `Output` of this `async fn`, found opaque type
    = note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:16:24>)
-              found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:22:25>)
+              found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:18:25>)
    = note: distinct uses of `impl Trait` result in different opaque types
 help: consider `await`ing on both `Future`s
    |
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 c4668444c4bbb17abaecd316d58beff0ab16df18..9ebf222ee342fe6f5607c182e9bb6055e3f88c37 100644 (file)
@@ -3,7 +3,7 @@ error: missing `struct` for struct definition
    |
 LL | pub onion {
    |    ^
--Ztrack-diagnostics: created at compiler/rustc_parse/src/parser/diagnostics.rs:LL:CC
+-Ztrack-diagnostics: created at compiler/rustc_parse/src/parser/item.rs:LL:CC
    |
 help: add `struct` here to parse `onion` as a public struct
    |
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/traits/new-solver/pointer-like.rs b/tests/ui/traits/new-solver/pointer-like.rs
new file mode 100644 (file)
index 0000000..3745a07
--- /dev/null
@@ -0,0 +1,14 @@
+// compile-flags: -Ztrait-solver=next
+
+#![feature(pointer_like_trait)]
+
+use std::marker::PointerLike;
+
+fn require_(_: impl PointerLike) {}
+
+fn main() {
+    require_(1usize);
+    require_(1u16);
+    //~^ ERROR `u16` needs to have the same alignment and size as a pointer
+    require_(&1i16);
+}
diff --git a/tests/ui/traits/new-solver/pointer-like.stderr b/tests/ui/traits/new-solver/pointer-like.stderr
new file mode 100644 (file)
index 0000000..f695e64
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0277]: `u16` needs to have the same alignment and size as a pointer
+  --> $DIR/pointer-like.rs:11:14
+   |
+LL |     require_(1u16);
+   |     -------- ^^^^ the trait `PointerLike` is not implemented for `u16`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: the trait bound `u16: PointerLike` is not satisfied
+note: required by a bound in `require_`
+  --> $DIR/pointer-like.rs:7:21
+   |
+LL | fn require_(_: impl PointerLike) {}
+   |                     ^^^^^^^^^^^ required by this bound in `require_`
+help: consider borrowing here
+   |
+LL |     require_(&1u16);
+   |              +
+LL |     require_(&mut 1u16);
+   |              ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/new-solver/pointer-sized.rs b/tests/ui/traits/new-solver/pointer-sized.rs
deleted file mode 100644 (file)
index 15681cd..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#![feature(pointer_sized_trait)]
-
-use std::marker::PointerSized;
-
-fn require_pointer_sized(_: impl PointerSized) {}
-
-fn main() {
-    require_pointer_sized(1usize);
-    require_pointer_sized(1u16);
-    //~^ ERROR `u16` needs to be a pointer-sized type
-    require_pointer_sized(&1i16);
-}
diff --git a/tests/ui/traits/new-solver/pointer-sized.stderr b/tests/ui/traits/new-solver/pointer-sized.stderr
deleted file mode 100644 (file)
index b250b13..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-error[E0277]: `u16` needs to be a pointer-sized type
-  --> $DIR/pointer-sized.rs:9:27
-   |
-LL |     require_pointer_sized(1u16);
-   |     --------------------- ^^^^ the trait `PointerSized` is not implemented for `u16`
-   |     |
-   |     required by a bound introduced by this call
-   |
-   = note: the trait bound `u16: PointerSized` is not satisfied
-note: required by a bound in `require_pointer_sized`
-  --> $DIR/pointer-sized.rs:5:34
-   |
-LL | fn require_pointer_sized(_: impl PointerSized) {}
-   |                                  ^^^^^^^^^^^^ required by this bound in `require_pointer_sized`
-help: consider borrowing here
-   |
-LL |     require_pointer_sized(&1u16);
-   |                           +
-LL |     require_pointer_sized(&mut 1u16);
-   |                           ++++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
index e9457c8faff4d349bad987563af0f9862c163cbc..22c6175048a63ecff25877a248f98d99c970b54a 100644 (file)
@@ -4,7 +4,7 @@ error: internal compiler error: delayed span bug triggered by #[rustc_error(dela
 LL | fn main() {}
    | ^^^^^^^^^
 
-error: internal compiler error: unexpected panic
+error: the compiler unexpectedly panicked. this is a bug.
 
 query stack during panic:
 #0 [trigger_delay_span_bug] triggering a delay span bug
index 8f67571c2990ea56a1c2494fd2331fb36cb5423f..3a56445a26b58102caea740bef520fef157f3a00 100644 (file)
@@ -4,7 +4,7 @@ error[E0080]: could not evaluate static initializer
 LL | pub static C: u32 = 0 - 1;
    |                     ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
 
-error: internal compiler error: unexpected panic
+error: the compiler unexpectedly panicked. this is a bug.
 
 query stack during panic:
 #0 [eval_to_allocation_raw] const-evaluating + checking `C`
index c5a4b5217d7a0aaddfb240ceb422f3fbceb180d3..bb9dd2365ea0d5de834978e859d5006c4fb3cd4f 100644 (file)
@@ -4,11 +4,6 @@ error[E0271]: expected `test` to be a fn item that returns `Pin<Box<dyn Future<O
 LL |     Box::new(test) as AsyncFnPtr;
    |     ^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found opaque type
    |
-note: while checking the return type of the `async fn`
-  --> $DIR/issue-98604.rs:5:17
-   |
-LL | async fn test() {}
-   |                 ^ checked the `Output` of this `async fn`, found opaque type
    = note:   expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
            found opaque type `impl Future<Output = ()>`
    = note: required for the cast from `fn() -> impl Future<Output = ()> {test}` to the object type `dyn Fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>>`
diff --git a/tests/ui/typeck/issue-107775.rs b/tests/ui/typeck/issue-107775.rs
new file mode 100644 (file)
index 0000000..6fbac2e
--- /dev/null
@@ -0,0 +1,40 @@
+// edition: 2021
+
+use std::collections::HashMap;
+use std::future::Future;
+use std::pin::Pin;
+
+pub trait Trait {
+    fn do_something<'async_trait>(byte: u8)
+    ->
+        Pin<Box<dyn Future<Output = ()> +
+        Send + 'async_trait>>;
+}
+
+pub struct Struct;
+
+impl Trait for Struct {
+    fn do_something<'async_trait>(byte: u8)
+        ->
+            Pin<Box<dyn Future<Output = ()> +
+            Send + 'async_trait>> {
+        Box::pin(
+
+            async move { let byte = byte; let _: () = {}; })
+    }
+}
+
+pub struct Map {
+    map: HashMap<u16, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
+}
+
+impl Map {
+    pub fn new() -> Self {
+        let mut map = HashMap::new();
+        map.insert(1, Struct::do_something);
+        Self { map }
+        //~^ ERROR mismatched types
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/issue-107775.stderr b/tests/ui/typeck/issue-107775.stderr
new file mode 100644 (file)
index 0000000..9ee9c02
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-107775.rs:35:16
+   |
+LL |         map.insert(1, Struct::do_something);
+   |                    -  -------------------- this is of type `fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}`, which causes `map` to be inferred as `HashMap<{integer}, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+   |                    |
+   |                    this is of type `{integer}`, which causes `map` to be inferred as `HashMap<{integer}, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+LL |         Self { map }
+   |                ^^^ expected `HashMap<u16, fn(u8) -> Pin<...>>`, found `HashMap<{integer}, ...>`
+   |
+   = note: expected struct `HashMap<u16, fn(_) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>>`
+              found struct `HashMap<{integer}, fn(_) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/issue-89856.fixed b/tests/ui/typeck/issue-89856.fixed
new file mode 100644 (file)
index 0000000..3e1a006
--- /dev/null
@@ -0,0 +1,18 @@
+// run-rustfix
+
+fn take_str_maybe(_: Option<&str>) { }
+fn main() {
+    let string = String::from("Hello, world");
+
+    let option: Option<String> = Some(string.clone());
+    take_str_maybe(option.as_deref());
+    //~^ ERROR: mismatched types [E0308]
+
+    let option_ref = Some(&string);
+    take_str_maybe(option_ref.map(|x| x.as_str()));
+    //~^ ERROR: mismatched types [E0308]
+
+    let option_ref_ref = option_ref.as_ref();
+    take_str_maybe(option_ref_ref.map(|x| x.as_str()));
+    //~^ ERROR: mismatched types [E0308]
+}
index b021e349e358c1f9ac83745c8d1ce2b014e0a34d..cfe6e19b303f3513578ae2d493f65f95d27911b5 100644 (file)
@@ -1,8 +1,18 @@
-fn take_str_maybe(x: Option<&str>) -> Option<&str> { None }
+// run-rustfix
 
+fn take_str_maybe(_: Option<&str>) { }
 fn main() {
     let string = String::from("Hello, world");
-    let option = Some(&string);
+
+    let option: Option<String> = Some(string.clone());
     take_str_maybe(option);
     //~^ ERROR: mismatched types [E0308]
+
+    let option_ref = Some(&string);
+    take_str_maybe(option_ref);
+    //~^ ERROR: mismatched types [E0308]
+
+    let option_ref_ref = option_ref.as_ref();
+    take_str_maybe(option_ref_ref);
+    //~^ ERROR: mismatched types [E0308]
 }
index 6b9cbe52c255300fdd61db687ba281ea477e6e70..bd76f17246821cd0cbbc82ddfc731276ba072382 100644 (file)
@@ -1,23 +1,63 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-89856.rs:6:20
+  --> $DIR/issue-89856.rs:8:20
    |
 LL |     take_str_maybe(option);
-   |     -------------- ^^^^^^ expected `Option<&str>`, found `Option<&String>`
+   |     -------------- ^^^^^^ expected `Option<&str>`, found `Option<String>`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected enum `Option<&str>`
+              found enum `Option<String>`
+note: function defined here
+  --> $DIR/issue-89856.rs:3:4
+   |
+LL | fn take_str_maybe(_: Option<&str>) { }
+   |    ^^^^^^^^^^^^^^ ---------------
+help: try converting the passed type into a `&str`
+   |
+LL |     take_str_maybe(option.as_deref());
+   |                          +++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-89856.rs:12:20
+   |
+LL |     take_str_maybe(option_ref);
+   |     -------------- ^^^^^^^^^^ expected `Option<&str>`, found `Option<&String>`
    |     |
    |     arguments to this function are incorrect
    |
    = note: expected enum `Option<&str>`
               found enum `Option<&String>`
 note: function defined here
-  --> $DIR/issue-89856.rs:1:4
+  --> $DIR/issue-89856.rs:3:4
+   |
+LL | fn take_str_maybe(_: Option<&str>) { }
+   |    ^^^^^^^^^^^^^^ ---------------
+help: try converting the passed type into a `&str`
+   |
+LL |     take_str_maybe(option_ref.map(|x| x.as_str()));
+   |                              ++++++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-89856.rs:16:20
+   |
+LL |     take_str_maybe(option_ref_ref);
+   |     -------------- ^^^^^^^^^^^^^^ expected `Option<&str>`, found `Option<&&String>`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected enum `Option<&str>`
+              found enum `Option<&&String>`
+note: function defined here
+  --> $DIR/issue-89856.rs:3:4
    |
-LL | fn take_str_maybe(x: Option<&str>) -> Option<&str> { None }
+LL | fn take_str_maybe(_: Option<&str>) { }
    |    ^^^^^^^^^^^^^^ ---------------
 help: try converting the passed type into a `&str`
    |
-LL |     take_str_maybe(option.map(|x| &**x));
-   |                          ++++++++++++++
+LL |     take_str_maybe(option_ref_ref.map(|x| x.as_str()));
+   |                                  ++++++++++++++++++++
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
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`.
diff --git a/tests/ui/uninhabited/issue-107505.rs b/tests/ui/uninhabited/issue-107505.rs
new file mode 100644 (file)
index 0000000..6159854
--- /dev/null
@@ -0,0 +1,18 @@
+// compile-flags: --crate-type=lib
+// check-pass
+
+// Make sure we don't pass inference variables to uninhabitedness checks in borrowck
+
+struct Command<'s> {
+    session: &'s (),
+    imp: std::convert::Infallible,
+}
+
+fn command(_: &()) -> Command<'_> {
+    unreachable!()
+}
+
+fn with_session<'s>(a: &std::process::Command, b: &'s ()) -> Command<'s> {
+    a.get_program();
+    command(b)
+}
diff --git a/tests/ui/unpretty/ast-const-trait-bound.rs b/tests/ui/unpretty/ast-const-trait-bound.rs
new file mode 100644 (file)
index 0000000..dbcba78
--- /dev/null
@@ -0,0 +1,4 @@
+// compile-flags: -Zunpretty=normal
+// check-pass
+
+fn foo() where T: ~const Bar {}
diff --git a/tests/ui/unpretty/ast-const-trait-bound.stdout b/tests/ui/unpretty/ast-const-trait-bound.stdout
new file mode 100644 (file)
index 0000000..dbcba78
--- /dev/null
@@ -0,0 +1,4 @@
+// compile-flags: -Zunpretty=normal
+// check-pass
+
+fn foo() where T: ~const Bar {}
diff --git a/tests/ui/where-clauses/self-in-where-clause-allowed.rs b/tests/ui/where-clauses/self-in-where-clause-allowed.rs
new file mode 100644 (file)
index 0000000..6cf5ed2
--- /dev/null
@@ -0,0 +1,23 @@
+// check-fail
+
+#![feature(auto_traits)]
+#![deny(where_clauses_object_safety)]
+
+auto trait AutoTrait {}
+
+trait Trait {
+    fn static_lifetime_bound(&self) where Self: 'static {}
+
+    fn arg_lifetime_bound<'a>(&self, _arg: &'a ()) where Self: 'a {}
+
+    fn autotrait_bound(&self) where Self: AutoTrait {}
+}
+
+impl Trait for () {}
+
+fn main() {
+    let trait_object = &() as &dyn Trait;
+    trait_object.static_lifetime_bound();
+    trait_object.arg_lifetime_bound(&());
+    trait_object.autotrait_bound(); //~ ERROR: the trait bound `dyn Trait: AutoTrait` is not satisfied
+}
diff --git a/tests/ui/where-clauses/self-in-where-clause-allowed.stderr b/tests/ui/where-clauses/self-in-where-clause-allowed.stderr
new file mode 100644 (file)
index 0000000..ea51f50
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `dyn Trait: AutoTrait` is not satisfied
+  --> $DIR/self-in-where-clause-allowed.rs:22:18
+   |
+LL |     trait_object.autotrait_bound();
+   |                  ^^^^^^^^^^^^^^^ the trait `AutoTrait` is not implemented for `dyn Trait`
+   |
+note: required by a bound in `Trait::autotrait_bound`
+  --> $DIR/self-in-where-clause-allowed.rs:13:43
+   |
+LL |     fn autotrait_bound(&self) where Self: AutoTrait {}
+   |                                           ^^^^^^^^^ required by this bound in `Trait::autotrait_bound`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
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",
 ]
diff --git a/x.py b/x.py
index 6df4033d55d7273bd064cedbddf4c959ee1dd301..5dee953a31899ff46fe3f459de48d8249ce2a4b2 100755 (executable)
--- a/x.py
+++ b/x.py
@@ -22,7 +22,8 @@ if sys.version_info.major < 3:
             pass
 
 rust_dir = os.path.dirname(os.path.abspath(__file__))
-sys.path.append(os.path.join(rust_dir, "src", "bootstrap"))
+# For the import below, have Python search in src/bootstrap first.
+sys.path.insert(0, os.path.join(rust_dir, "src", "bootstrap"))
 
 import bootstrap
 bootstrap.main()